diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6ac8f90
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+bin/
+gen/
+libs/
+obj/
diff --git a/README.rdoc b/README.rdoc
new file mode 100644
index 0000000..61b16e8
--- /dev/null
+++ b/README.rdoc
@@ -0,0 +1,75 @@
+= 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 1.6 and NDK r5. It may or may not work with a higher / lower version. It has been confirmed that this doesn't work with older versions of Android SDK, 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)
+* The QuickTime Java Libraries (optional if you want to use the QTWebcamBroadcaster)
+
+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 now even easier with NDK r5. I'm going to assume that you are familiar with Android if you are reading this and keep it rather short.
+
+* Make sure that ndk-build is in your path.
+
+* Go to the OpenCV-Android project directory and run 'ndk-build'
+
+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.
+
+NOTE: 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.
+
+IMPORTANT NEW NOTE: In order for the QTWebcamBroadcaster to work, you must ensure that you run it in a 32-bit VM. Failure to run in 32-bit will result in an empty screen in your emulator (no image will appear.) You can easily force the VM that runs this application to 32-bit by adding the VM flag:
+-d32
+
+
+== 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.
+
+NOTE: 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/index.html b/index.html
deleted file mode 100644
index 564a9d7..0000000
--- a/index.html
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
- billmccord/OpenCV-Android @ GitHub
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A project for porting and optimizing OpenCV for Google's Android OS
-
-
-
Dependencies
-
Android SDK and NDK
-
Authors
-
Noritsuna Imamura (noritsuna@siprop.org)
-
Bill McCord (bill.mccord@intuitiveautomata.com)
-
Contact
-
(bill.mccord@intuitiveautomata.com) (noritsuna@siprop.org)
-
-
-
-
Download
-
- You can download this project in either
- zip or
- tar formats.
-
-
You can also clone the project with Git
- by running:
-
$ git clone git://github.com/billmccord/OpenCV-Android
-
-
-
-
-
-
-
-
-
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100755
index 0000000..50b090b
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,276 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cxcore
+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 := cv
+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 := cvaux
+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 := cvml
+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 := cvhighgui
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cv/src \
+ $(LOCAL_PATH)/cv/include \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/otherlibs/highgui
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
+
+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 := opencv
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cv/src \
+ $(LOCAL_PATH)/cv/include \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/cvaux/src \
+ $(LOCAL_PATH)/cvaux/include \
+ $(LOCAL_PATH)/ml/include \
+ $(LOCAL_PATH)/otherlibs/highgui
+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 \
+ cvjni.cpp
+
+
+LOCAL_STATIC_LIBRARIES := cxcore cv cvaux cvml cvhighgui
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/jni/Application.mk b/jni/Application.mk
new file mode 100755
index 0000000..c63938e
--- /dev/null
+++ b/jni/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/jni/LICENSE_Android_NDK b/jni/LICENSE_Android_NDK
new file mode 100755
index 0000000..6d379b3
--- /dev/null
+++ b/jni/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/jni/LICENSE_OpenCV b/jni/LICENSE_OpenCV
new file mode 100644
index 0000000..3f81081
--- /dev/null
+++ b/jni/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/jni/WLNonFileByteStream.cpp b/jni/WLNonFileByteStream.cpp
new file mode 100755
index 0000000..138c174
--- /dev/null
+++ b/jni/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/jni/WLNonFileByteStream.h b/jni/WLNonFileByteStream.h
new file mode 100755
index 0000000..5ae8b75
--- /dev/null
+++ b/jni/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
+#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/jni/cv/include/cv.h b/jni/cv/include/cv.h
new file mode 100755
index 0000000..02ec454
--- /dev/null
+++ b/jni/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
+ #include
+ 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(xnext[(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 .
+ After that sum of histogram bins is equal to */
+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 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 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/jni/cv/include/cv.hpp b/jni/cv/include/cv.hpp
new file mode 100755
index 0000000..882c946
--- /dev/null
+++ b/jni/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/jni/cv/include/cvcompat.h b/jni/cv/include/cvcompat.h
new file mode 100755
index 0000000..976a711
--- /dev/null
+++ b/jni/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
+
+#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/jni/cv/include/cvstreams.h b/jni/cv/include/cvstreams.h
new file mode 100755
index 0000000..0bb205d
--- /dev/null
+++ b/jni/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 /* !!! 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 \samples\multimedia\directshow\readme.txt.
+
+4. Copy the built libraries (called strmbase.lib and strmbasd.lib
+ in Release and Debug versions, respectively) to
+ \lib.
+
+5. In Developer Studio add the following paths:
+ \include
+ \include
+ \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
+ \lib
+ \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/jni/cv/include/cvtypes.h b/jni/cv/include/cvtypes.h
new file mode 100755
index 0000000..e45cae2
--- /dev/null
+++ b/jni/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
+ #include
+#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|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/jni/cv/src/_cv.h b/jni/cv/src/_cv.h
new file mode 100755
index 0000000..4687bc3
--- /dev/null
+++ b/jni/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
+#include
+#include
+#include
+#include
+#include
+#include
+
+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/jni/cv/src/_cvgeom.h b/jni/cv/src/_cvgeom.h
new file mode 100755
index 0000000..e2849aa
--- /dev/null
+++ b/jni/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/jni/cv/src/_cvimgproc.h b/jni/cv/src/_cvimgproc.h
new file mode 100755
index 0000000..bccb873
--- /dev/null
+++ b/jni/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/jni/cv/src/_cvipp.h b/jni/cv/src/_cvipp.h
new file mode 100755
index 0000000..47fd1c6
--- /dev/null
+++ b/jni/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/jni/cv/src/_cvkdtree.hpp b/jni/cv/src/_cvkdtree.hpp
new file mode 100755
index 0000000..2d34622
--- /dev/null
+++ b/jni/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
+
+#ifndef __cv_kdtree_h__
+#define __cv_kdtree_h__
+
+#include "_cv.h"
+
+#include
+#include
+#include
+#include
+#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/jni/cv/src/_cvlist.h b/jni/cv/src/_cvlist.h
new file mode 100755
index 0000000..b2b63e9
--- /dev/null
+++ b/jni/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
+#include
+
+#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/jni/cv/src/_cvmatrix.h b/jni/cv/src/_cvmatrix.h
new file mode 100755
index 0000000..af4c591
--- /dev/null
+++ b/jni/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/jni/cv/src/cvaccum.cpp b/jni/cv/src/cvaccum.cpp
new file mode 100755
index 0000000..21b715f
--- /dev/null
+++ b/jni/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/jni/cv/src/cvadapthresh.cpp b/jni/cv/src/cvadapthresh.cpp
new file mode 100755
index 0000000..30d4733
--- /dev/null
+++ b/jni/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/jni/cv/src/cvapprox.cpp b/jni/cv/src/cvapprox.cpp
new file mode 100755
index 0000000..d26ecd4
--- /dev/null
+++ b/jni/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/jni/cv/src/cvcalccontrasthistogram.cpp b/jni/cv/src/cvcalccontrasthistogram.cpp
new file mode 100755
index 0000000..36a44b3
--- /dev/null
+++ b/jni/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/jni/cv/src/cvcalcimagehomography.cpp b/jni/cv/src/cvcalcimagehomography.cpp
new file mode 100755
index 0000000..e820dfc
--- /dev/null
+++ b/jni/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( ¢er, &rz );
+
+ /* calculate (I - r_trans)*center */
+ cvSetIdentity( &sub );
+ cvSub( &sub, &r_trans, &sub );
+ cvMatMul( &sub, ¢er, &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/jni/cv/src/cvcalibinit.cpp b/jni/cv/src/cvcalibinit.cpp
new file mode 100755
index 0000000..bc43238
--- /dev/null
+++ b/jni/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.
+ pgruebele@cox.net
+
+ 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
+
+//#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; icount == 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; irow = 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; icount == 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; icount < 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 that isn't present,
+// tries to add it in.
+// 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; iordered)
+ 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; iordered)
+ 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 has value
+//
+
+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( ¢ers );
+
+ 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<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/jni/cv/src/cvcamshift.cpp b/jni/cv/src/cvcamshift.cpp
new file mode 100755
index 0000000..41fbebd
--- /dev/null
+++ b/jni/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/jni/cv/src/cvcanny.cpp b/jni/cv/src/cvcanny.cpp
new file mode 100755
index 0000000..92b6dc3
--- /dev/null
+++ b/jni/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< 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/jni/cv/src/cvcolor.cpp b/jni/cv/src/cvcolor.cpp
new file mode 100755
index 0000000..87baa1c
--- /dev/null
+++ b/jni/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< 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/jni/cv/src/cvcondens.cpp b/jni/cv/src/cvcondens.cpp
new file mode 100755
index 0000000..cf0d2a8
--- /dev/null
+++ b/jni/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)&&(jSamplesNum-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/jni/cv/src/cvcontours.cpp b/jni/cv/src/cvcontours.cpp
new file mode 100755
index 0000000..63652b9
--- /dev/null
+++ b/jni/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
+ ( , 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;
+
+ ( temp_contour, contour_storage,
+ &new_contour, );
+
+ 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 +/- 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/jni/cv/src/cvcontourtree.cpp b/jni/cv/src/cvcontourtree.cpp
new file mode 100755
index 0000000..a3d99c8
--- /dev/null
+++ b/jni/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/jni/cv/src/cvconvhull.cpp b/jni/cv/src/cvconvhull.cpp
new file mode 100755
index 0000000..eafc568
--- /dev/null
+++ b/jni/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/jni/cv/src/cvcorner.cpp b/jni/cv/src/cvcorner.cpp
new file mode 100755
index 0000000..b2ce599
--- /dev/null
+++ b/jni/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
+
+
+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/jni/cv/src/cvcornersubpix.cpp b/jni/cv/src/cvcornersubpix.cpp
new file mode 100755
index 0000000..5eb282c
--- /dev/null
+++ b/jni/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/jni/cv/src/cvderiv.cpp b/jni/cv/src/cvderiv.cpp
new file mode 100755
index 0000000..b373f83
--- /dev/null
+++ b/jni/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/jni/cv/src/cvdistransform.cpp b/jni/cv/src/cvdistransform.cpp
new file mode 100755
index 0000000..51452f5
--- /dev/null
+++ b/jni/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/jni/cv/src/cvdominants.cpp b/jni/cv/src/cvdominants.cpp
new file mode 100755
index 0000000..6ac6f69
--- /dev/null
+++ b/jni/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/jni/cv/src/cvemd.cpp b/jni/cv/src/cvemd.cpp
new file mode 100755
index 0000000..82be363
--- /dev/null
+++ b/jni/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/jni/cv/src/cvfeatureselect.cpp b/jni/cv/src/cvfeatureselect.cpp
new file mode 100755
index 0000000..acda3fc
--- /dev/null
+++ b/jni/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/jni/cv/src/cvfilter.cpp b/jni/cv/src/cvfilter.cpp
new file mode 100755
index 0000000..f95fcca
--- /dev/null
+++ b/jni/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/jni/cv/src/cvfloodfill.cpp b/jni/cv/src/cvfloodfill.cpp
new file mode 100755
index 0000000..ca6425a
--- /dev/null
+++ b/jni/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/jni/cv/src/cvfundam.cpp b/jni/cv/src/cvfundam.cpp
new file mode 100755
index 0000000..42adabf
--- /dev/null
+++ b/jni/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 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/jni/cv/src/cvgeometry.cpp b/jni/cv/src/cvgeometry.cpp
new file mode 100755
index 0000000..1f1c0d1
--- /dev/null
+++ b/jni/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/jni/cv/src/cvhaar.cpp b/jni/cv/src/cvhaar.cpp
new file mode 100755
index 0000000..06fa5cd
--- /dev/null
+++ b/jni/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
+
+/* 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/jni/cv/src/cvhistogram.cpp b/jni/cv/src/cvhistogram.cpp
new file mode 100755
index 0000000..cb9552b
--- /dev/null
+++ b/jni/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 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 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 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; idims; 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; ithresh[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; ithresh[i], 2, "f" );
+ }
+ }
+ else{
+ for(i=0; ithresh2[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/jni/cv/src/cvhough.cpp b/jni/cv/src/cvhough.cpp
new file mode 100755
index 0000000..ea2d4f2
--- /dev/null
+++ b/jni/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/jni/cv/src/cvimgwarp.cpp b/jni/cv/src/cvimgwarp.cpp
new file mode 100755
index 0000000..65c0d8f
--- /dev/null
+++ b/jni/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)<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/jni/cv/src/cvinpaint.cpp b/jni/cv/src/cvinpaint.cpp
new file mode 100755
index 0000000..fbf471c
--- /dev/null
+++ b/jni/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; irows; i++) {
+ for (j=0; jcols; 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; irows; i++) {
+ for(j=0; jcols; 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&&krows-1&&lcols-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&&krows-1&&lcols-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&&krows-1&&lcols-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&&krows-1&&lcols-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; jcols; j++) {\
+ CV_MAT_ELEM(*image,type,0,j) = value;\
+ }\
+ for (i=1; irows-1; i++) {\
+ CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\
+ }\
+ for(j=0; jcols; j++) {\
+ CV_MAT_ELEM(*image,type,erows-1,j) = value;\
+ }\
+ }
+
+#define COPY_MASK_BORDER1_C1(src,dst,type) {\
+ int i,j;\
+ for (i=0; irows; i++) {\
+ for(j=0; jcols; 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/jni/cv/src/cvkalman.cpp b/jni/cv/src/cvkalman.cpp
new file mode 100755
index 0000000..c82214b
--- /dev/null
+++ b/jni/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/jni/cv/src/cvkdtree.cpp b/jni/cv/src/cvkdtree.cpp
new file mode 100755
index 0000000..7fd702d
--- /dev/null
+++ b/jni/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
+
+#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
+ 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 > tree_type; c; break; } \
+ case CV_64F: \
+ { typedef CvKDTree > tree_type; c; break; } \
+ default: assert(0); \
+ }
+
+ CvMat* mat;
+ void* data;
+
+ template
+ 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
+ int find_ortho_range(CvMat* bounds_min, CvMat* bounds_max,
+ CvMat* results) {
+ int rn = results->rows * results->cols;
+ std::vector 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 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
+ (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
+ (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/jni/cv/src/cvlinefit.cpp b/jni/cv/src/cvlinefit.cpp
new file mode 100755
index 0000000..4095c80
--- /dev/null
+++ b/jni/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/jni/cv/src/cvlkpyramid.cpp b/jni/cv/src/cvlkpyramid.cpp
new file mode 100755
index 0000000..f5ad42d
--- /dev/null
+++ b/jni/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
+#include
+
+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 = + */
+ 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 = + */
+ 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 = + */
+ 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/jni/cv/src/cvmatchcontours.cpp b/jni/cv/src/cvmatchcontours.cpp
new file mode 100755
index 0000000..a4a6938
--- /dev/null
+++ b/jni/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/jni/cv/src/cvmoments.cpp b/jni/cv/src/cvmoments.cpp
new file mode 100755
index 0000000..fc66d31
--- /dev/null
+++ b/jni/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/jni/cv/src/cvmorph.cpp b/jni/cv/src/cvmorph.cpp
new file mode 100755
index 0000000..9a2899e
--- /dev/null
+++ b/jni/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
+#include
+
+#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/jni/cv/src/cvmotempl.cpp b/jni/cv/src/cvmotempl.cpp
new file mode 100755
index 0000000..1792671
--- /dev/null
+++ b/jni/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/jni/cv/src/cvoptflowbm.cpp b/jni/cv/src/cvoptflowbm.cpp
new file mode 100755
index 0000000..723e3aa
--- /dev/null
+++ b/jni/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/jni/cv/src/cvoptflowhs.cpp b/jni/cv/src/cvoptflowhs.cpp
new file mode 100755
index 0000000..77aa6f9
--- /dev/null
+++ b/jni/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/jni/cv/src/cvoptflowlk.cpp b/jni/cv/src/cvoptflowlk.cpp
new file mode 100755
index 0000000..065bfc8
--- /dev/null
+++ b/jni/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/jni/cv/src/cvpgh.cpp b/jni/cv/src/cvpgh.cpp
new file mode 100755
index 0000000..8caaf4f
--- /dev/null
+++ b/jni/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/jni/cv/src/cvposit.cpp b/jni/cv/src/cvposit.cpp
new file mode 100755
index 0000000..65da46d
--- /dev/null
+++ b/jni/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/jni/cv/src/cvprecomp.cpp b/jni/cv/src/cvprecomp.cpp
new file mode 100755
index 0000000..d304b17
--- /dev/null
+++ b/jni/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/jni/cv/src/cvpyramids.cpp b/jni/cv/src/cvpyramids.cpp
new file mode 100755
index 0000000..829c0c9
--- /dev/null
+++ b/jni/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/jni/cv/src/cvpyrsegmentation.cpp b/jni/cv/src/cvpyrsegmentation.cpp
new file mode 100755
index 0000000..4759d40
--- /dev/null
+++ b/jni/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/jni/cv/src/cvrotcalipers.cpp b/jni/cv/src/cvrotcalipers.cpp
new file mode 100755
index 0000000..a6564e1
--- /dev/null
+++ b/jni/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/jni/cv/src/cvsamplers.cpp b/jni/cv/src/cvsamplers.cpp
new file mode 100755
index 0000000..484fab7
--- /dev/null
+++ b/jni/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/jni/cv/src/cvsegmentation.cpp b/jni/cv/src/cvsegmentation.cpp
new file mode 100755
index 0000000..2bf66b8
--- /dev/null
+++ b/jni/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/jni/cv/src/cvshapedescr.cpp b/jni/cv/src/cvshapedescr.cpp
new file mode 100755
index 0000000..a4c2f88
--- /dev/null
+++ b/jni/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]], ¢er, &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, ¢er, &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/jni/cv/src/cvsmooth.cpp b/jni/cv/src/cvsmooth.cpp
new file mode 100755
index 0000000..55f8fea
--- /dev/null
+++ b/jni/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
+#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/jni/cv/src/cvsnakes.cpp b/jni/cv/src/cvsnakes.cpp
new file mode 100755
index 0000000..734e90a
--- /dev/null
+++ b/jni/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/jni/cv/src/cvstereobm.cpp b/jni/cv/src/cvstereobm.cpp
new file mode 100755
index 0000000..3e9f731
--- /dev/null
+++ b/jni/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/jni/cv/src/cvstereogc.cpp b/jni/cv/src/cvstereogc.cpp
new file mode 100755
index 0000000..0f6f806
--- /dev/null
+++ b/jni/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+(yfirst = 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/jni/cv/src/cvsubdivision2d.cpp b/jni/cv/src/cvsubdivision2d.cpp
new file mode 100755
index 0000000..99778e5
--- /dev/null
+++ b/jni/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/jni/cv/src/cvsumpixels.cpp b/jni/cv/src/cvsumpixels.cpp
new file mode 100755
index 0000000..3603468
--- /dev/null
+++ b/jni/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/jni/cv/src/cvsurf.cpp b/jni/cv/src/cvsurf.cpp
new file mode 100755
index 0000000..75b0f41
--- /dev/null
+++ b/jni/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, ¶ms );
+ 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/jni/cv/src/cvswitcher.cpp b/jni/cv/src/cvswitcher.cpp
new file mode 100755
index 0000000..bbcc4ff
--- /dev/null
+++ b/jni/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/jni/cv/src/cvtables.cpp b/jni/cv/src/cvtables.cpp
new file mode 100755
index 0000000..9fe7d81
--- /dev/null
+++ b/jni/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/jni/cv/src/cvtemplmatch.cpp b/jni/cv/src/cvtemplmatch.cpp
new file mode 100755
index 0000000..cd79528
--- /dev/null
+++ b/jni/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/jni/cv/src/cvthresh.cpp b/jni/cv/src/cvthresh.cpp
new file mode 100755
index 0000000..52ea622
--- /dev/null
+++ b/jni/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/jni/cv/src/cvundistort.cpp b/jni/cv/src/cvundistort.cpp
new file mode 100755
index 0000000..a84bcf7
--- /dev/null
+++ b/jni/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/jni/cv/src/cvutils.cpp b/jni/cv/src/cvutils.cpp
new file mode 100755
index 0000000..c88b309
--- /dev/null
+++ b/jni/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/jni/cv/src/mycvHaarDetectObjects.cpp b/jni/cv/src/mycvHaarDetectObjects.cpp
new file mode 100644
index 0000000..18b946c
--- /dev/null
+++ b/jni/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
+
+/* 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/jni/cvaux/include/cvaux.h b/jni/cvaux/include/cvaux.h
new file mode 100755
index 0000000..e102dc8
--- /dev/null
+++ b/jni/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/jni/cvaux/include/cvaux.hpp b/jni/cvaux/include/cvaux.hpp
new file mode 100755
index 0000000..37ae897
--- /dev/null
+++ b/jni/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/jni/cvaux/include/cvmat.hpp b/jni/cvaux/include/cvmat.hpp
new file mode 100755
index 0000000..5defb59
--- /dev/null
+++ b/jni/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
+#include
+
+#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/jni/cvaux/include/cvvidsurv.hpp b/jni/cvaux/include/cvvidsurv.hpp
new file mode 100755
index 0000000..373565d
--- /dev/null
+++ b/jni/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
+
+#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; itotal; ++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; itotal; ++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;itotal;++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; itotal; ++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; itotal; ++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 which must be the sequence of 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 );
+ /* must be the sequence of 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;bGetBlob(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/jni/cvaux/src/_cvaux.h b/jni/cvaux/src/_cvaux.h
new file mode 100755
index 0000000..65267d9
--- /dev/null
+++ b/jni/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/jni/cvaux/src/_cvfacedetection.h b/jni/cvaux/src/_cvfacedetection.h
new file mode 100755
index 0000000..8c41be4
--- /dev/null
+++ b/jni/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/jni/cvaux/src/_cvvectrack.h b/jni/cvaux/src/_cvvectrack.h
new file mode 100755
index 0000000..557a3f7
--- /dev/null
+++ b/jni/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
+#include
+#include
+#include
+
+#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/jni/cvaux/src/_cvvm.h b/jni/cvaux/src/_cvvm.h
new file mode 100755
index 0000000..940da5c
--- /dev/null
+++ b/jni/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/jni/cvaux/src/camshift.cpp b/jni/cvaux/src/camshift.cpp
new file mode 100755
index 0000000..23cff7d
--- /dev/null
+++ b/jni/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/jni/cvaux/src/cv3dtracker.cpp b/jni/cvaux/src/cv3dtracker.cpp
new file mode 100755
index 0000000..aa8a0e3
--- /dev/null
+++ b/jni/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
+#include