From 61c27ac81e1f900c2bcf598d973445edfc1950aa Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Mon, 23 Sep 2013 19:00:49 +0200 Subject: [PATCH 01/12] Shape module added --- modules/shape/CMakeLists.txt | 2 + modules/shape/doc/emdL1.rst | 11 + modules/shape/doc/histogram_cost_matrix.rst | 82 ++ modules/shape/doc/shape.rst | 15 + modules/shape/doc/shape.rst~ | 15 + modules/shape/doc/shape_distances.rst | 231 +++++ modules/shape/doc/shape_transformers.rst | 108 +++ modules/shape/include/opencv2/shape.hpp | 58 ++ modules/shape/include/opencv2/shape/emdL1.hpp | 58 ++ .../shape/include/opencv2/shape/hist_cost.hpp | 103 +++ modules/shape/include/opencv2/shape/shape.hpp | 48 + .../include/opencv2/shape/shape_distance.hpp | 143 +++ .../opencv2/shape/shape_transformer.hpp | 109 +++ modules/shape/src/aff_trans.cpp | 266 ++++++ modules/shape/src/emdL1.cpp | 794 ++++++++++++++++ modules/shape/src/emdL1_def.hpp | 142 +++ modules/shape/src/haus_dis.cpp | 151 ++++ modules/shape/src/hist_cost.cpp | 547 +++++++++++ modules/shape/src/precomp.cpp | 45 + modules/shape/src/precomp.hpp | 59 ++ modules/shape/src/sc_dis.cpp | 848 ++++++++++++++++++ modules/shape/src/tps_trans.cpp | 288 ++++++ modules/shape/test/test_emdl1.cpp | 266 ++++++ modules/shape/test/test_hausdorff.cpp | 280 ++++++ modules/shape/test/test_main.cpp | 3 + modules/shape/test/test_precomp.cpp | 1 + modules/shape/test/test_precomp.hpp | 21 + modules/shape/test/test_shape.cpp | 267 ++++++ samples/cpp/CMakeLists.txt | 2 +- samples/cpp/shape_example.cpp | 111 +++ samples/cpp/shape_sample/1.png | Bin 0 -> 705 bytes samples/cpp/shape_sample/10.png | Bin 0 -> 1024 bytes samples/cpp/shape_sample/11.png | Bin 0 -> 722 bytes samples/cpp/shape_sample/12.png | Bin 0 -> 437 bytes samples/cpp/shape_sample/13.png | Bin 0 -> 443 bytes samples/cpp/shape_sample/14.png | Bin 0 -> 1820 bytes samples/cpp/shape_sample/15.png | Bin 0 -> 803 bytes samples/cpp/shape_sample/16.png | Bin 0 -> 830 bytes samples/cpp/shape_sample/17.png | Bin 0 -> 3100 bytes samples/cpp/shape_sample/18.png | Bin 0 -> 3283 bytes samples/cpp/shape_sample/19.png | Bin 0 -> 1560 bytes samples/cpp/shape_sample/2.png | Bin 0 -> 813 bytes samples/cpp/shape_sample/20.png | Bin 0 -> 1571 bytes samples/cpp/shape_sample/3.png | Bin 0 -> 2301 bytes samples/cpp/shape_sample/4.png | Bin 0 -> 2431 bytes samples/cpp/shape_sample/5.png | Bin 0 -> 852 bytes samples/cpp/shape_sample/6.png | Bin 0 -> 969 bytes samples/cpp/shape_sample/7.png | Bin 0 -> 874 bytes samples/cpp/shape_sample/8.png | Bin 0 -> 851 bytes samples/cpp/shape_sample/9.png | Bin 0 -> 1204 bytes samples/cpp/shape_transformation.cpp | 74 ++ 51 files changed, 5147 insertions(+), 1 deletion(-) create mode 100644 modules/shape/CMakeLists.txt create mode 100644 modules/shape/doc/emdL1.rst create mode 100644 modules/shape/doc/histogram_cost_matrix.rst create mode 100644 modules/shape/doc/shape.rst create mode 100644 modules/shape/doc/shape.rst~ create mode 100644 modules/shape/doc/shape_distances.rst create mode 100644 modules/shape/doc/shape_transformers.rst create mode 100644 modules/shape/include/opencv2/shape.hpp create mode 100644 modules/shape/include/opencv2/shape/emdL1.hpp create mode 100644 modules/shape/include/opencv2/shape/hist_cost.hpp create mode 100644 modules/shape/include/opencv2/shape/shape.hpp create mode 100644 modules/shape/include/opencv2/shape/shape_distance.hpp create mode 100644 modules/shape/include/opencv2/shape/shape_transformer.hpp create mode 100644 modules/shape/src/aff_trans.cpp create mode 100644 modules/shape/src/emdL1.cpp create mode 100644 modules/shape/src/emdL1_def.hpp create mode 100644 modules/shape/src/haus_dis.cpp create mode 100644 modules/shape/src/hist_cost.cpp create mode 100644 modules/shape/src/precomp.cpp create mode 100644 modules/shape/src/precomp.hpp create mode 100644 modules/shape/src/sc_dis.cpp create mode 100644 modules/shape/src/tps_trans.cpp create mode 100644 modules/shape/test/test_emdl1.cpp create mode 100644 modules/shape/test/test_hausdorff.cpp create mode 100644 modules/shape/test/test_main.cpp create mode 100644 modules/shape/test/test_precomp.cpp create mode 100644 modules/shape/test/test_precomp.hpp create mode 100644 modules/shape/test/test_shape.cpp create mode 100644 samples/cpp/shape_example.cpp create mode 100644 samples/cpp/shape_sample/1.png create mode 100644 samples/cpp/shape_sample/10.png create mode 100644 samples/cpp/shape_sample/11.png create mode 100644 samples/cpp/shape_sample/12.png create mode 100644 samples/cpp/shape_sample/13.png create mode 100644 samples/cpp/shape_sample/14.png create mode 100644 samples/cpp/shape_sample/15.png create mode 100644 samples/cpp/shape_sample/16.png create mode 100644 samples/cpp/shape_sample/17.png create mode 100644 samples/cpp/shape_sample/18.png create mode 100644 samples/cpp/shape_sample/19.png create mode 100644 samples/cpp/shape_sample/2.png create mode 100644 samples/cpp/shape_sample/20.png create mode 100644 samples/cpp/shape_sample/3.png create mode 100644 samples/cpp/shape_sample/4.png create mode 100644 samples/cpp/shape_sample/5.png create mode 100644 samples/cpp/shape_sample/6.png create mode 100644 samples/cpp/shape_sample/7.png create mode 100644 samples/cpp/shape_sample/8.png create mode 100644 samples/cpp/shape_sample/9.png create mode 100644 samples/cpp/shape_transformation.cpp diff --git a/modules/shape/CMakeLists.txt b/modules/shape/CMakeLists.txt new file mode 100644 index 0000000000..77150c4dea --- /dev/null +++ b/modules/shape/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Shape descriptors and matchers.") +ocv_define_module(shape opencv_core opencv_imgproc opencv_video) diff --git a/modules/shape/doc/emdL1.rst b/modules/shape/doc/emdL1.rst new file mode 100644 index 0000000000..853756d0ca --- /dev/null +++ b/modules/shape/doc/emdL1.rst @@ -0,0 +1,11 @@ +EMD-L1 +====== +Computes the "minimal work" distance between two weighted point configurations base on the papers "EMD-L1: An efficient and Robust Algorithm +for comparing histogram-based descriptors", by Haibin Ling and Kazunori Okuda; and "The Earth Mover's Distance is the Mallows Distance: +Some Insights from Statistics", by Elizaveta Levina and Peter Bickel. + +.. ocv:function:: float EMDL1( InputArray signature1, InputArray signature2 ) + + :param signature1: First signature, a single column floating-point matrix. Each row is the value of the histogram in each bin. + + :param signature2: Second signature of the same format and size as ``signature1``. diff --git a/modules/shape/doc/histogram_cost_matrix.rst b/modules/shape/doc/histogram_cost_matrix.rst new file mode 100644 index 0000000000..9f6804dd0b --- /dev/null +++ b/modules/shape/doc/histogram_cost_matrix.rst @@ -0,0 +1,82 @@ +Cost Matrix for Histograms Common Interface +=========================================== + +.. highlight:: cpp + +A common interface is defined to ease the implementation of some algorithms pipelines, such +as the Shape Context Matching Algorithm. A common class is defined, so any object that implements +a Cost Matrix builder inherits the +:ocv:class:`HistogramCostExtractor` interface. + +HistogramCostExtractor +---------------------- +.. ocv:class:: HistogramCostExtractor : public Algorithm + +Abstract base class for histogram cost algorithms. :: + + class CV_EXPORTS_W HistogramCostExtractor : public Algorithm + { + public: + CV_WRAP virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix) = 0; + + CV_WRAP virtual void setNDummies(int nDummies) = 0; + CV_WRAP virtual int getNDummies() const = 0; + + CV_WRAP virtual void setDefaultCost(float defaultCost) = 0; + CV_WRAP virtual float getDefaultCost() const = 0; + }; + +NormHistogramCostExtractor +-------------------------- +.. ocv:class:: NormHistogramCostExtractor : public HistogramCostExtractor + +A norm based cost extraction. :: + + class CV_EXPORTS_W NormHistogramCostExtractor : public HistogramCostExtractor + { + public: + CV_WRAP virtual void setNormFlag(int flag) = 0; + CV_WRAP virtual int getNormFlag() const = 0; + }; + + CV_EXPORTS_W Ptr + createNormHistogramCostExtractor(int flag=cv::DIST_L2, int nDummies=25, float defaultCost=0.2); + +EMDHistogramCostExtractor +------------------------- +.. ocv:class:: EMDHistogramCostExtractor : public HistogramCostExtractor + +An EMD based cost extraction. :: + + class CV_EXPORTS_W EMDHistogramCostExtractor : public HistogramCostExtractor + { + public: + CV_WRAP virtual void setNormFlag(int flag) = 0; + CV_WRAP virtual int getNormFlag() const = 0; + }; + + CV_EXPORTS_W Ptr + createEMDHistogramCostExtractor(int flag=cv::DIST_L2, int nDummies=25, float defaultCost=0.2); + +ChiHistogramCostExtractor +------------------------- +.. ocv:class:: ChiHistogramCostExtractor : public HistogramCostExtractor + +An Chi based cost extraction. :: + + class CV_EXPORTS_W ChiHistogramCostExtractor : public HistogramCostExtractor + {}; + + CV_EXPORTS_W Ptr createChiHistogramCostExtractor(int nDummies=25, float defaultCost=0.2); + +EMDL1HistogramCostExtractor +------------------------- +.. ocv:class:: EMDL1HistogramCostExtractor : public HistogramCostExtractor + +An EMD-L1 based cost extraction. :: + + class CV_EXPORTS_W EMDL1HistogramCostExtractor : public HistogramCostExtractor + {}; + + CV_EXPORTS_W Ptr + createEMDL1HistogramCostExtractor(int nDummies=25, float defaultCost=0.2); diff --git a/modules/shape/doc/shape.rst b/modules/shape/doc/shape.rst new file mode 100644 index 0000000000..663a8b2e1e --- /dev/null +++ b/modules/shape/doc/shape.rst @@ -0,0 +1,15 @@ +********************************** +shape. Shape Distance and Matching +********************************** + +The module contains algorithms that embed a notion of shape distance. +These algorithms may be used for shape matching and retrieval, or shape +comparison. + +.. toctree:: + :maxdepth: 2 + + shape_distances + shape_transformers + histogram_cost_matrix + emdL1 diff --git a/modules/shape/doc/shape.rst~ b/modules/shape/doc/shape.rst~ new file mode 100644 index 0000000000..b18968556b --- /dev/null +++ b/modules/shape/doc/shape.rst~ @@ -0,0 +1,15 @@ +***** +shape +***** + +The module contains algorithms that embed a notion of shape distance. +These algorithms may be used for shape matching and retrieval, or shape +comparison. + +.. toctree:: + :maxdepth: 2 + + shape_distances + shape_transformers + histogram_cost_matrix + emdL1 diff --git a/modules/shape/doc/shape_distances.rst b/modules/shape/doc/shape_distances.rst new file mode 100644 index 0000000000..c671e97ed5 --- /dev/null +++ b/modules/shape/doc/shape_distances.rst @@ -0,0 +1,231 @@ +Shape Distance and Common Interfaces +==================================== + +.. highlight:: cpp + +Shape Distance algorithms in OpenCV are derivated from a common interface that allows you to +switch between them in a practical way for solving the same problem with different methods. +Thus, all objects that implement shape distance measures inherit the +:ocv:class:`ShapeDistanceExtractor` interface. + + +ShapeDistanceExtractor +---------------------- +.. ocv:class:: ShapeDistanceExtractor : public Algorithm + +Abstract base class for shape distance algorithms. :: + + class CV_EXPORTS_W ShapeDistanceExtractor : public Algorithm + { + public: + CV_WRAP virtual float computeDistance(InputArray contour1, InputArray contour2) = 0; + }; + +ShapeDistanceExtractor::computeDistance +--------------------------------------- +Compute the shape distance between two shapes defined by its contours. + +.. ocv:function:: float ShapeDistanceExtractor::computeDistance( InputArray contour1, InputArray contour2 ) + + :param contour1: Contour defining first shape. + + :param contour2: Contour defining second shape. + +ShapeContextDistanceExtractor +----------------------------- +.. ocv:class:: ShapeContextDistanceExtractor : public ShapeDistanceExtractor + +Implementation of the Shape Context descriptor and matching algorithm proposed by Belongie et al. in +"Shape Matching and Object Recognition Using Shape Contexts" (PAMI 2002). +This implementation is packaged in a generic scheme, in order to allow you the implementation of the +common variations of the original pipeline. :: + + class CV_EXPORTS_W ShapeContextDistanceExtractor : public ShapeDistanceExtractor + { + public: + CV_WRAP virtual void setAngularBins(int nAngularBins) = 0; + CV_WRAP virtual int getAngularBins() const = 0; + + CV_WRAP virtual void setRadialBins(int nRadialBins) = 0; + CV_WRAP virtual int getRadialBins() const = 0; + + CV_WRAP virtual void setInnerRadius(float innerRadius) = 0; + CV_WRAP virtual float getInnerRadius() const = 0; + + CV_WRAP virtual void setOuterRadius(float outerRadius) = 0; + CV_WRAP virtual float getOuterRadius() const = 0; + + CV_WRAP virtual void setRotationInvariant(bool rotationInvariant) = 0; + CV_WRAP virtual bool getRotationInvariant() const = 0; + + CV_WRAP virtual void setShapeContextWeight(float shapeContextWeight) = 0; + CV_WRAP virtual float getShapeContextWeight() const = 0; + + CV_WRAP virtual void setImageAppearanceWeight(float imageAppearanceWeight) = 0; + CV_WRAP virtual float getImageAppearanceWeight() const = 0; + + CV_WRAP virtual void setBendingEnergyWeight(float bendingEnergyWeight) = 0; + CV_WRAP virtual float getBendingEnergyWeight() const = 0; + + CV_WRAP virtual void setImages(InputArray image1, InputArray image2) = 0; + CV_WRAP virtual void getImages(OutputArray image1, OutputArray image2) const = 0; + + CV_WRAP virtual void setIterations(int iterations) = 0; + CV_WRAP virtual int getIterations() const = 0; + + CV_WRAP virtual void setCostExtractor(Ptr comparer) = 0; + CV_WRAP virtual Ptr getCostExtractor() const = 0; + + CV_WRAP virtual void setTransformAlgorithm(Ptr transformer) = 0; + CV_WRAP virtual Ptr getTransformAlgorithm() const = 0; + }; + + /* Complete constructor */ + CV_EXPORTS_W Ptr + createShapeContextDistanceExtractor(int nAngularBins=12, int nRadialBins=4, + float innerRadius=0.2, float outerRadius=2, int iterations=3, + const Ptr &comparer = createChiHistogramCostExtractor(), + const Ptr &transformer = createThinPlateSplineShapeTransformer()); + +ShapeContextDistanceExtractor::setAngularBins +--------------------------------------------- +Establish the number of angular bins for the Shape Context Descriptor used in the shape matching pipeline. + +.. ocv:function:: void setAngularBins( int nAngularBins ) + + :param nAngularBins: The number of angular bins in the shape context descriptor. + +ShapeContextDistanceExtractor::setRadialBins +-------------------------------------------- +Establish the number of radial bins for the Shape Context Descriptor used in the shape matching pipeline. + +.. ocv:function:: void setRadialBins( int nRadialBins ) + + :param nRadialBins: The number of radial bins in the shape context descriptor. + +ShapeContextDistanceExtractor::setInnerRadius +--------------------------------------------- +Set the inner radius of the shape context descriptor. + +.. ocv:function:: void setInnerRadius(float innerRadius) + + :param innerRadius: The value of the inner radius. + +ShapeContextDistanceExtractor::setOuterRadius +--------------------------------------------- +Set the outer radius of the shape context descriptor. + +.. ocv:function:: void setOuterRadius(float outerRadius) + + :param outerRadius: The value of the outer radius. + +ShapeContextDistanceExtractor::setShapeContextWeight +---------------------------------------------------- +Set the weight of the shape context distance in the final value of the shape distance. +The shape context distance between two shapes is defined as the symmetric sum of shape +context matching costs over best matching points. +The final value of the shape distance is a user-defined linear combination of the shape +context distance, an image appearance distance, and a bending energy. + +.. ocv:function:: void setShapeContextWeight( float shapeContextWeight ) + + :param shapeContextWeight: The weight of the shape context distance in the final distance value. + +ShapeContextDistanceExtractor::setImageAppearanceWeight +------------------------------------------------------- +Set the weight of the Image Appearance cost in the final value of the shape distance. +The image appearance cost is defined as the sum of squared brightness differences in +Gaussian windows around corresponding image points. +The final value of the shape distance is a user-defined linear combination of the shape +context distance, an image appearance distance, and a bending energy. +If this value is set to a number different from 0, is mandatory to set the images that +correspond to each shape. + +.. ocv:function:: void setImageAppearanceWeight( float imageAppearanceWeight ) + + :param imageAppearanceWeight: The weight of the appearance cost in the final distance value. + +ShapeContextDistanceExtractor::setBendingEnergyWeight +----------------------------------------------------- +Set the weight of the Bending Energy in the final value of the shape distance. +The bending energy definition depends on what transformation is being used to align the +shapes. +The final value of the shape distance is a user-defined linear combination of the shape +context distance, an image appearance distance, and a bending energy. + +.. ocv:function:: void setBendingEnergyWeight( float bendingEnergyWeight ) + + :param bendingEnergyWeight: The weight of the Bending Energy in the final distance value. + +ShapeContextDistanceExtractor::setImages +---------------------------------------- +Set the images that correspond to each shape. This images are used in the calculation of the +Image Appearance cost. + +.. ocv:function:: void setImages( InputArray image1, InputArray image2 ) + + :param image1: Image corresponding to the shape defined by ``contours1``. + + :param image2: Image corresponding to the shape defined by ``contours2``. + +ShapeContextDistanceExtractor::setCostExtractor +----------------------------------------------- +Set the algorithm used for building the shape context descriptor cost matrix. + +.. ocv:function:: void setCostExtractor( Ptr comparer ) + + :param comparer: Smart pointer to a HistogramCostExtractor, an algorithm that defines the cost matrix between descriptors. + +ShapeContextDistanceExtractor::setStdDev +---------------------------------------- +Set the value of the standard deviation for the Gaussian window for the image appearance cost. + +.. ocv:function:: void setStdDev( float sigma ) + + :param sigma: Standard Deviation. + +ShapeContextDistanceExtractor::setTransformAlgorithm +---------------------------------------------------- +Set the algorithm used for aligning the shapes. + +.. ocv:function:: void setTransformAlgorithm( Ptr transformer ) + + :param comparer: Smart pointer to a ShapeTransformer, an algorithm that defines the aligning transformation. + +HausdorffDistanceExtractor +-------------------------- +.. ocv:class:: HausdorffDistanceExtractor : public ShapeDistanceExtractor + +A simple Hausdorff distance measure between shapes defined by contours, +according to the paper "Comparing Images using the Hausdorff distance." by +D.P. Huttenlocher, G.A. Klanderman, and W.J. Rucklidge. (PAMI 1993). :: + + class CV_EXPORTS_W HausdorffDistanceExtractor : public ShapeDistanceExtractor + { + public: + CV_WRAP virtual void setDistanceFlag(int distanceFlag) = 0; + CV_WRAP virtual int getDistanceFlag() const = 0; + + CV_WRAP virtual void setRankProportion(float rankProportion) = 0; + CV_WRAP virtual float getRankProportion() const = 0; + }; + + /* Constructor */ + CV_EXPORTS_W Ptr createHausdorffDistanceExtractor(int distanceFlag=cv::NORM_L2, float rankProp=0.6); + +HausdorffDistanceExtractor::setDistanceFlag +------------------------------------------- +Set the norm used to compute the Hausdorff value between two shapes. It can be L1 or L2 norm. + +.. ocv:function:: void setDistanceFlag( int distanceFlag ) + + :param distanceFlag: Flag indicating which norm is used to compute the Hausdorff distance (NORM_L1, NORM_L2). + +HausdorffDistanceExtractor::setRankProportion +--------------------------------------------- +This method sets the rank proportion (or fractional value) that establish the Kth ranked value of the +partial Hausdorff distance. Experimentally had been shown that 0.6 is a good value to compare shapes. + +.. ocv:function:: void setRankProportion( float rankProportion ) + + :param rankProportion: fractional value (between 0 and 1). diff --git a/modules/shape/doc/shape_transformers.rst b/modules/shape/doc/shape_transformers.rst new file mode 100644 index 0000000000..b1d2026023 --- /dev/null +++ b/modules/shape/doc/shape_transformers.rst @@ -0,0 +1,108 @@ +Shape Transformers and Interfaces +================================= + +.. highlight:: cpp + +A virtual interface that ease the use of transforming algorithms in some pipelines, such as +the Shape Context Matching Algorithm. Thus, all objects that implement shape transformation +techniques inherit the +:ocv:class:`ShapeTransformer` interface. + +ShapeTransformer +---------------- +.. ocv:class:: ShapeTransformer : public Algorithm + +Abstract base class for shape transformation algorithms. :: + + class CV_EXPORTS_W ShapeTransformer : public Algorithm + { + public: + CV_WRAP virtual void estimateTransformation(InputArray transformingShape, InputArray targetShape, + std::vector& matches) = 0; + + CV_WRAP virtual float applyTransformation(InputArray input, OutputArray output=noArray()) = 0; + + CV_WRAP virtual void warpImage(InputArray transformingImage, OutputArray output, + int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, + const Scalar& borderValue=Scalar()) const = 0; + }; + +ShapeTransformer::estimateTransformation +---------------------------------------- +Estimate the transformation parameters of the current transformer algorithm, based on point matches. + +.. ocv:function:: void estimateTransformation( InputArray transformingShape, InputArray targetShape, std::vector& matches ) + + :param transformingShape: Contour defining first shape. + + :param targetShape: Contour defining second shape (Target). + + :param matches: Standard vector of Matches between points. + +ShapeTransformer::applyTransformation +------------------------------------- +Apply a transformation, given a pre-estimated transformation parameters. + +.. ocv:function:: float applyTransformation( InputArray input, OutputArray output=noArray() ) + + :param input: Contour (set of points) to apply the transformation. + + :param output: Output contour. + +ShapeTransformer::warpImage +--------------------------- +Apply a transformation, given a pre-estimated transformation parameters, to an Image. + +.. ocv:function:: void warpImage( InputArray transformingImage, OutputArray output, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar() ) + + :param transformingImage: Input image. + + :param output: Output image. + + :param flags: Image interpolation method. + + :param borderMode: border style. + + :param borderValue: border value. + +ThinPlateSplineShapeTransformer +------------------------------- +.. ocv:class:: ThinPlateSplineShapeTransformer : public Algorithm + +Definition of the transformation ocupied in the paper "Principal Warps: Thin-Plate Splines and Decomposition +of Deformations", by F.L. Bookstein (PAMI 1989). :: + + class CV_EXPORTS_W ThinPlateSplineShapeTransformer : public ShapeTransformer + { + public: + CV_WRAP virtual void setRegularizationParameter(double beta) = 0; + CV_WRAP virtual double getRegularizationParameter() const = 0; + }; + + /* Complete constructor */ + CV_EXPORTS_W Ptr + createThinPlateSplineShapeTransformer(double regularizationParameter=0); + +ThinPlateSplineShapeTransformer::setRegularizationParameter +----------------------------------------------------------- +Set the regularization parameter for relaxing the exact interpolation requirements of the TPS algorithm. + +.. ocv:function:: void setRegularizationParameter( double beta ) + + :param beta: value of the regularization parameter. + +AffineTransformer +----------------- +.. ocv:class:: AffineTransformer : public Algorithm + +Wrapper class for the OpenCV Affine Transformation algorithm. :: + + class CV_EXPORTS_W AffineTransformer : public ShapeTransformer + { + public: + CV_WRAP virtual void setFullAffine(bool fullAffine) = 0; + CV_WRAP virtual bool getFullAffine() const = 0; + }; + + /* Complete constructor */ + CV_EXPORTS_W Ptr createAffineTransformer(bool fullAffine); diff --git a/modules/shape/include/opencv2/shape.hpp b/modules/shape/include/opencv2/shape.hpp new file mode 100644 index 0000000000..d07bf5e453 --- /dev/null +++ b/modules/shape/include/opencv2/shape.hpp @@ -0,0 +1,58 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_SHAPE_HPP__ +#define __OPENCV_SHAPE_HPP__ + +#include "opencv2/shape/emdL1.hpp" +#include "opencv2/shape/shape_transformer.hpp" +#include "opencv2/shape/hist_cost.hpp" +#include "opencv2/shape/shape_distance.hpp" + +namespace cv +{ +CV_EXPORTS bool initModule_shape(); +} + +#endif + +/* End of file. */ diff --git a/modules/shape/include/opencv2/shape/emdL1.hpp b/modules/shape/include/opencv2/shape/emdL1.hpp new file mode 100644 index 0000000000..400d26b261 --- /dev/null +++ b/modules/shape/include/opencv2/shape/emdL1.hpp @@ -0,0 +1,58 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_EMD_L1_HPP__ +#define __OPENCV_EMD_L1_HPP__ + +#include "opencv2/core.hpp" + +namespace cv +{ +/****************************************************************************************\ +* EMDL1 Function * +\****************************************************************************************/ + +CV_EXPORTS float EMDL1(InputArray signature1, InputArray signature2); + +}//namespace cv + +#endif diff --git a/modules/shape/include/opencv2/shape/hist_cost.hpp b/modules/shape/include/opencv2/shape/hist_cost.hpp new file mode 100644 index 0000000000..9ca3825fda --- /dev/null +++ b/modules/shape/include/opencv2/shape/hist_cost.hpp @@ -0,0 +1,103 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_HIST_COST_HPP__ +#define __OPENCV_HIST_COST_HPP__ + +#include "opencv2/imgproc.hpp" + +namespace cv +{ + +/*! + * The base class for HistogramCostExtractor. + */ +class CV_EXPORTS_W HistogramCostExtractor : public Algorithm +{ +public: + CV_WRAP virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix) = 0; + + CV_WRAP virtual void setNDummies(int nDummies) = 0; + CV_WRAP virtual int getNDummies() const = 0; + + CV_WRAP virtual void setDefaultCost(float defaultCost) = 0; + CV_WRAP virtual float getDefaultCost() const = 0; +}; + +/*! */ +class CV_EXPORTS_W NormHistogramCostExtractor : public HistogramCostExtractor +{ +public: + CV_WRAP virtual void setNormFlag(int flag) = 0; + CV_WRAP virtual int getNormFlag() const = 0; +}; + +CV_EXPORTS_W Ptr + createNormHistogramCostExtractor(int flag=DIST_L2, int nDummies=25, float defaultCost=0.2); + +/*! */ +class CV_EXPORTS_W EMDHistogramCostExtractor : public HistogramCostExtractor +{ +public: + CV_WRAP virtual void setNormFlag(int flag) = 0; + CV_WRAP virtual int getNormFlag() const = 0; +}; + +CV_EXPORTS_W Ptr + createEMDHistogramCostExtractor(int flag=DIST_L2, int nDummies=25, float defaultCost=0.2); + +/*! */ +class CV_EXPORTS_W ChiHistogramCostExtractor : public HistogramCostExtractor +{}; + +CV_EXPORTS_W Ptr createChiHistogramCostExtractor(int nDummies=25, float defaultCost=0.2); + +/*! */ +class CV_EXPORTS_W EMDL1HistogramCostExtractor : public HistogramCostExtractor +{}; + +CV_EXPORTS_W Ptr + createEMDL1HistogramCostExtractor(int nDummies=25, float defaultCost=0.2); + +} // cv +#endif diff --git a/modules/shape/include/opencv2/shape/shape.hpp b/modules/shape/include/opencv2/shape/shape.hpp new file mode 100644 index 0000000000..5c4da3cefa --- /dev/null +++ b/modules/shape/include/opencv2/shape/shape.hpp @@ -0,0 +1,48 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifdef __OPENCV_BUILD +#error this is a compatibility header which should not be used inside the OpenCV library +#endif + +#include "opencv2/shape.hpp" diff --git a/modules/shape/include/opencv2/shape/shape_distance.hpp b/modules/shape/include/opencv2/shape/shape_distance.hpp new file mode 100644 index 0000000000..55e21aaa4a --- /dev/null +++ b/modules/shape/include/opencv2/shape/shape_distance.hpp @@ -0,0 +1,143 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__ +#define __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__ +#include "opencv2/core.hpp" +#include "opencv2/shape/hist_cost.hpp" +#include "opencv2/shape/shape_transformer.hpp" + +namespace cv +{ + +/*! + * The base class for ShapeDistanceExtractor. + * This is just to define the common interface for + * shape comparisson techniques. + */ +class CV_EXPORTS_W ShapeDistanceExtractor : public Algorithm +{ +public: + CV_WRAP virtual float computeDistance(InputArray contour1, InputArray contour2) = 0; +}; + +/***********************************************************************************/ +/***********************************************************************************/ +/***********************************************************************************/ +/*! + * Shape Context implementation. + * The SCD class implements SCD algorithm proposed by Belongie et al.in + * "Shape Matching and Object Recognition Using Shape Contexts". + * Implemented by Juan M. Perez for the GSOC 2013. + */ +class CV_EXPORTS_W ShapeContextDistanceExtractor : public ShapeDistanceExtractor +{ +public: + CV_WRAP virtual void setAngularBins(int nAngularBins) = 0; + CV_WRAP virtual int getAngularBins() const = 0; + + CV_WRAP virtual void setRadialBins(int nRadialBins) = 0; + CV_WRAP virtual int getRadialBins() const = 0; + + CV_WRAP virtual void setInnerRadius(float innerRadius) = 0; + CV_WRAP virtual float getInnerRadius() const = 0; + + CV_WRAP virtual void setOuterRadius(float outerRadius) = 0; + CV_WRAP virtual float getOuterRadius() const = 0; + + CV_WRAP virtual void setRotationInvariant(bool rotationInvariant) = 0; + CV_WRAP virtual bool getRotationInvariant() const = 0; + + CV_WRAP virtual void setShapeContextWeight(float shapeContextWeight) = 0; + CV_WRAP virtual float getShapeContextWeight() const = 0; + + CV_WRAP virtual void setImageAppearanceWeight(float imageAppearanceWeight) = 0; + CV_WRAP virtual float getImageAppearanceWeight() const = 0; + + CV_WRAP virtual void setBendingEnergyWeight(float bendingEnergyWeight) = 0; + CV_WRAP virtual float getBendingEnergyWeight() const = 0; + + CV_WRAP virtual void setImages(InputArray image1, InputArray image2) = 0; + CV_WRAP virtual void getImages(OutputArray image1, OutputArray image2) const = 0; + + CV_WRAP virtual void setIterations(int iterations) = 0; + CV_WRAP virtual int getIterations() const = 0; + + CV_WRAP virtual void setCostExtractor(Ptr comparer) = 0; + CV_WRAP virtual Ptr getCostExtractor() const = 0; + + CV_WRAP virtual void setStdDev(float sigma) = 0; + CV_WRAP virtual float getStdDev() const = 0; + + CV_WRAP virtual void setTransformAlgorithm(Ptr transformer) = 0; + CV_WRAP virtual Ptr getTransformAlgorithm() const = 0; +}; + +/* Complete constructor */ +CV_EXPORTS_W Ptr + createShapeContextDistanceExtractor(int nAngularBins=12, int nRadialBins=4, + float innerRadius=0.2, float outerRadius=2, int iterations=3, + const Ptr &comparer = createChiHistogramCostExtractor(), + const Ptr &transformer = createThinPlateSplineShapeTransformer()); + +/***********************************************************************************/ +/***********************************************************************************/ +/***********************************************************************************/ +/*! + * Hausdorff distace implementation based on + */ +class CV_EXPORTS_W HausdorffDistanceExtractor : public ShapeDistanceExtractor +{ +public: + CV_WRAP virtual void setDistanceFlag(int distanceFlag) = 0; + CV_WRAP virtual int getDistanceFlag() const = 0; + + CV_WRAP virtual void setRankProportion(float rankProportion) = 0; + CV_WRAP virtual float getRankProportion() const = 0; +}; + +/* Constructor */ +CV_EXPORTS_W Ptr createHausdorffDistanceExtractor(int distanceFlag=cv::NORM_L2, float rankProp=0.6); + +} // cv +#endif diff --git a/modules/shape/include/opencv2/shape/shape_transformer.hpp b/modules/shape/include/opencv2/shape/shape_transformer.hpp new file mode 100644 index 0000000000..cdabf971c7 --- /dev/null +++ b/modules/shape/include/opencv2/shape/shape_transformer.hpp @@ -0,0 +1,109 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__ +#define __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__ +#include +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" + +namespace cv +{ + +/*! + * The base class for ShapeTransformer. + * This is just to define the common interface for + * shape transformation techniques. + */ +class CV_EXPORTS_W ShapeTransformer : public Algorithm +{ +public: + /* Estimate, Apply Transformation and return Transforming cost*/ + CV_WRAP virtual void estimateTransformation(InputArray transformingShape, InputArray targetShape, + std::vector& matches) = 0; + + CV_WRAP virtual float applyTransformation(InputArray input, OutputArray output=noArray()) = 0; + + CV_WRAP virtual void warpImage(InputArray transformingImage, OutputArray output, + int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, + const Scalar& borderValue=Scalar()) const = 0; +}; + +/***********************************************************************************/ +/***********************************************************************************/ +/*! + * Thin Plate Spline Transformation + * Implementation of the TPS transformation + * according to "Principal Warps: Thin-Plate Splines and the + * Decomposition of Deformations" by Juan Manuel Perez for the GSOC 2013 + */ + +class CV_EXPORTS_W ThinPlateSplineShapeTransformer : public ShapeTransformer +{ +public: + CV_WRAP virtual void setRegularizationParameter(double beta) = 0; + CV_WRAP virtual double getRegularizationParameter() const = 0; +}; + +/* Complete constructor */ +CV_EXPORTS_W Ptr + createThinPlateSplineShapeTransformer(double regularizationParameter=0); + +/***********************************************************************************/ +/***********************************************************************************/ +/*! + * Affine Transformation as a derivated from ShapeTransformer + */ + +class CV_EXPORTS_W AffineTransformer : public ShapeTransformer +{ +public: + CV_WRAP virtual void setFullAffine(bool fullAffine) = 0; + CV_WRAP virtual bool getFullAffine() const = 0; +}; + +/* Complete constructor */ +CV_EXPORTS_W Ptr createAffineTransformer(bool fullAffine); + +} // cv +#endif diff --git a/modules/shape/src/aff_trans.cpp b/modules/shape/src/aff_trans.cpp new file mode 100644 index 0000000000..c416b82056 --- /dev/null +++ b/modules/shape/src/aff_trans.cpp @@ -0,0 +1,266 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "precomp.hpp" + +namespace cv +{ + +class AffineTransformerImpl : public AffineTransformer +{ +public: + /* Constructors */ + AffineTransformerImpl() + { + fullAffine = true; + name_ = "ShapeTransformer.AFF"; + } + + AffineTransformerImpl(bool _fullAffine) + { + fullAffine = _fullAffine; + name_ = "ShapeTransformer.AFF"; + } + + /* Destructor */ + ~AffineTransformerImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual void estimateTransformation(InputArray transformingShape, InputArray targetShape, std::vector &matches); + virtual float applyTransformation(InputArray input, OutputArray output=noArray()); + virtual void warpImage(InputArray transformingImage, OutputArray output, + int flags, int borderMode, const Scalar& borderValue) const; + + //! Setters/Getters + virtual void setFullAffine(bool _fullAffine) {fullAffine=_fullAffine;} + virtual bool getFullAffine() const {return fullAffine;} + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "affine_type" << fullAffine; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + fullAffine = (int)fn["affine_type"]; + } + +private: + bool fullAffine; + Mat affineMat; + float transformCost; + +protected: + String name_; +}; + +void AffineTransformerImpl::warpImage(InputArray transformingImage, OutputArray output, + int flags, int borderMode, const Scalar& borderValue) const +{ + CV_Assert(!affineMat.empty()); + warpAffine(transformingImage, output, affineMat, transformingImage.getMat().size(), flags, borderMode, borderValue); +} + + +static Mat _localAffineEstimate(const std::vector& shape1, const std::vector& shape2, + bool fullAfine) +{ + Mat out(2,3,CV_32F); + int siz=2*shape1.size(); + + if (fullAfine) + { + Mat matM(siz, 6, CV_32F); + Mat matP(siz,1,CV_32F); + int contPt=0; + for (int ii=0; ii(0,0)=shape1[contPt].x; + therow.at(0,1)=shape1[contPt].y; + therow.at(0,2)=1; + therow.row(0).copyTo(matM.row(ii)); + matP.at(ii,0) = shape2[contPt].x; + } + else + { + therow.at(0,3)=shape1[contPt].x; + therow.at(0,4)=shape1[contPt].y; + therow.at(0,5)=1; + therow.row(0).copyTo(matM.row(ii)); + matP.at(ii,0) = shape2[contPt].y; + contPt++; + } + } + Mat sol; + solve(matM, matP, sol, DECOMP_SVD); + out = sol.reshape(0,2); + } + else + { + Mat matM(siz, 4, CV_32F); + Mat matP(siz,1,CV_32F); + int contPt=0; + for (int ii=0; ii(0,0)=shape1[contPt].x; + therow.at(0,1)=shape1[contPt].y; + therow.at(0,2)=1; + therow.row(0).copyTo(matM.row(ii)); + matP.at(ii,0) = shape2[contPt].x; + } + else + { + therow.at(0,0)=-shape1[contPt].y; + therow.at(0,1)=shape1[contPt].x; + therow.at(0,3)=1; + therow.row(0).copyTo(matM.row(ii)); + matP.at(ii,0) = shape2[contPt].y; + contPt++; + } + } + Mat sol; + solve(matM, matP, sol, DECOMP_SVD); + out.at(0,0)=sol.at(0,0); + out.at(0,1)=sol.at(1,0); + out.at(0,2)=sol.at(2,0); + out.at(1,0)=-sol.at(1,0); + out.at(1,1)=sol.at(0,0); + out.at(1,2)=sol.at(3,0); + } + return out; +} + +void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray _pts2, std::vector& _matches) +{ + Mat pts1 = _pts1.getMat(); + Mat pts2 = _pts2.getMat(); + CV_Assert((pts1.channels()==2) & (pts1.cols>0) & (pts2.channels()==2) & (pts2.cols>0)); + CV_Assert(_matches.size()>1); + + if (pts1.type() != CV_32F) + pts1.convertTo(pts1, CV_32F); + if (pts2.type() != CV_32F) + pts2.convertTo(pts2, CV_32F); + + // Use only valid matchings // + std::vector matches; + for (size_t i=0; i<_matches.size(); i++) + { + if (_matches[i].queryIdx shape1; // transforming shape + std::vector shape2; // target shape + for (size_t i=0; i(0,matches[i].queryIdx); + shape1.push_back(pt1); + + Point2f pt2=pts2.at(0,matches[i].trainIdx); + shape2.push_back(pt2); + } + + // estimateRigidTransform // + Mat affine; + estimateRigidTransform(shape1, shape2, fullAffine).convertTo(affine, CV_32F); + + if (affine.empty()) + affine=_localAffineEstimate(shape1, shape2, fullAffine); //In case there is not good solution, just give a LLS based one + + affineMat = affine; +} + +float AffineTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts) +{ + Mat pts1 = inPts.getMat(); + CV_Assert((pts1.channels()==2) & (pts1.cols>0)); + + //Apply transformation in the complete set of points + Mat fAffine; + transform(pts1, fAffine, affineMat); + + // Ensambling output // + if (outPts.needed()) + { + outPts.create(1,fAffine.cols, CV_32FC2); + Mat outMat = outPts.getMat(); + for (int i=0; i(0,i)=fAffine.at(0,i); + } + + // Updating Transform Cost // + Mat Af(2, 2, CV_32F); + Af.at(0,0)=affineMat.at(0,0); + Af.at(0,1)=affineMat.at(1,0); + Af.at(1,0)=affineMat.at(0,1); + Af.at(1,1)=affineMat.at(1,1); + SVD mysvd(Af, SVD::NO_UV); + Mat singVals=mysvd.w; + transformCost=std::log((singVals.at(0,0)+FLT_MIN)/(singVals.at(1,0)+FLT_MIN)); + + return transformCost; +} + +Ptr createAffineTransformer(bool fullAffine) +{ + return Ptr( new AffineTransformerImpl(fullAffine) ); +} + +} // cv diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp new file mode 100644 index 0000000000..cdd903e1ab --- /dev/null +++ b/modules/shape/src/emdL1.cpp @@ -0,0 +1,794 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* + * Implementation of an optimized EMD for histograms based in + * the papers "EMD-L1: An efficient and Robust Algorithm + * for comparing histogram-based descriptors", by Haibin Ling and + * Kazunori Okuda; and "The Earth Mover's Distance is the Mallows + * Distance: Some Insights from Statistics", by Elizaveta Levina and + * Peter Bickel, based on HAIBIN LING AND KAZUNORI OKADA implementation. + */ + +#include "precomp.hpp" +#include "emdL1_def.hpp" + + +/****************************************************************************************\ +* EMDL1 Class * +\****************************************************************************************/ + +float EmdL1::getEMDL1(cv::Mat &sig1, cv::Mat &sig2) +{ + // Initialization + CV_Assert((sig1.rows==sig2.rows) & (sig1.cols==sig2.cols) & (!sig1.empty()) & (!sig2.empty())); + if(!initBaseTrees(sig1.rows, 1)) + return -1; + + float *H1=new float[sig1.rows], *H2 = new float[sig2.rows]; + for (int ii=0; ii(ii,0); + H2[ii]=sig2.at(ii,0); + } + + fillBaseTrees(H1,H2); // Initialize histograms + greedySolution(); // Construct an initial Basic Feasible solution + initBVTree(); // Initialize BVTree + + // Iteration + bool bOptimal = false; + m_nItr = 0; + while(!bOptimal && m_nItrpChild); + + // Optimality test + bOptimal = isOptimal(); + + // Find new solution + if(!bOptimal) + findNewSolution(); + ++m_nItr; + } + delete [] H1; + delete [] H2; + // Output the total flow + return compuTotalFlow(); +} + +void EmdL1::setMaxIteration(int _nMaxIt) +{ + nMaxIt=_nMaxIt; +} + +//-- SubFunctions called in the EMD algorithm +bool EmdL1::initBaseTrees(int n1, int n2, int n3) +{ + if(binsDim1==n1 && binsDim2==n2 && binsDim3==n3) + return true; + binsDim1 = n1; + binsDim2 = n2; + binsDim3 = n3; + if(binsDim1==0 || binsDim2==0) dimension = 0; + else dimension = (binsDim3==0)?2:3; + + if(dimension==2) + { + m_Nodes.resize(binsDim1); + m_EdgesUp.resize(binsDim1); + m_EdgesRight.resize(binsDim1); + for(int i1=0; i1 d2s(binsDim2); + d2s[0] = 0; + for(c=0; c d1s(binsDim1); + d1s[0] = 0; + for(r=0; r fabs(dFlow+d1s[r+1])); // Move upward or right + + // modify basic variables, record BV and related values + if(bUpward) + { + // move to up + pBV = &(m_EdgesUp[r][c]); + m_NBVEdges[nNBV++] = &(m_EdgesRight[r][c]); + D[r+1][c] += dFlow; // auxilary matrix maintanence + d1s[r+1] += dFlow; // auxilary matrix maintanence + } + else + { + // move to right, no other choice + pBV = &(m_EdgesRight[r][c]); + if(rpParent->pChild = pBV; + pBV->flow = fabs(dFlow); + pBV->iDir = dFlow>0; // 1:outward, 0:inward + } + + //- rightmost column, no choice but move upward + c = binsDim2-1; + for(r=0; rpParent->pChild= pBV; + pBV->flow = fabs(dFlow); + pBV->iDir = dFlow>0; // 1:outward, 0:inward + } + return true; +} + +bool EmdL1::greedySolution3() +{ + //- Prepare auxiliary array, D=H1-H2 + int i1,i2,i3; + std::vector D(binsDim1); + for(i1=0; i1 d1s(binsDim1); + d1s[0] = 0; + for(i1=0; i1 d2s(binsDim2); + d2s[0] = 0; + for(i2=0; i2 d3s(binsDim3); + d3s[0] = 0; + for(i3=0; i3flow = fabs(dFlow); + pBV->iDir = dFlow>0; // 1:outward, 0:inward + pBV->pParent->pChild= pBV; + } + } + } + return true; +} + +void EmdL1::initBVTree() +{ + // initialize BVTree from the initial BF solution + //- Using the center of the graph as the root + int r = (int)(0.5*binsDim1-.5); + int c = (int)(0.5*binsDim2-.5); + int z = (int)(0.5*binsDim3-.5); + m_pRoot = dimension==2 ? &(m_Nodes[r][c]) : &(m_3dNodes[r][c][z]); + m_pRoot->u = 0; + m_pRoot->iLevel = 0; + m_pRoot->pParent= NULL; + m_pRoot->pPEdge = NULL; + + //- Prepare a queue + m_auxQueue[0] = m_pRoot; + int nQueue = 1; // length of queue + int iQHead = 0; // head of queue + + //- Recursively build subtrees + cvPEmdEdge pCurE=NULL, pNxtE=NULL; + cvPEmdNode pCurN=NULL, pNxtN=NULL; + int nBin = binsDim1*binsDim2*std::max(binsDim3,1); + while(iQHeadpos[0]; + c = pCurN->pos[1]; + z = pCurN->pos[2]; + + // check connection from itself + pCurE = pCurN->pChild; // the initial child from initial solution + if(pCurE) + { + pNxtN = pCurE->pChild; + pNxtN->pParent = pCurN; + pNxtN->pPEdge = pCurE; + m_auxQueue[nQueue++] = pNxtN; + } + + // check four neighbor nodes + int nNB = dimension==2?4:6; + for(int k=0;k0) pNxtN = &(m_Nodes[r][c-1]); // left + else if(k==1 && r>0) pNxtN = &(m_Nodes[r-1][c]); // down + else if(k==2 && c0) pNxtN = &(m_3dNodes[r][c-1][z]); // left + else if(k==1 && c0) pNxtN = &(m_3dNodes[r-1][c][z]); // down + else if(k==3 && r0) pNxtN = &(m_3dNodes[r][c][z-1]); // shallow + else if(k==5 && zpParent) + { + pNxtE = pNxtN->pChild; + if(pNxtE && pNxtE->pChild==pCurN) // has connection + { + pNxtN->pParent = pCurN; + pNxtN->pPEdge = pNxtE; + pNxtN->pChild = NULL; + m_auxQueue[nQueue++] = pNxtN; + + pNxtE->pParent = pCurN; // reverse direction + pNxtE->pChild = pNxtN; + pNxtE->iDir = !pNxtE->iDir; + + if(pCurE) pCurE->pNxt = pNxtE; // add to edge list + else pCurN->pChild = pNxtE; + pCurE = pNxtE; + } + } + } + } +} + +void EmdL1::updateSubtree(cvPEmdNode pRoot) +{ + // Initialize auxiliary queue + m_auxQueue[0] = pRoot; + int nQueue = 1; // queue length + int iQHead = 0; // head of queue + + // BFS browing + cvPEmdNode pCurN=NULL,pNxtN=NULL; + cvPEmdEdge pCurE=NULL; + while(iQHeadpChild; + + // browsing all children + while(pCurE) + { + pNxtN = pCurE->pChild; + pNxtN->iLevel = pCurN->iLevel+1; + pNxtN->u = pCurE->iDir ? (pCurN->u - 1) : (pCurN->u + 1); + pCurE = pCurE->pNxt; + m_auxQueue[nQueue++] = pNxtN; + } + } +} + +bool EmdL1::isOptimal() +{ + int iC, iMinC = 0; + cvPEmdEdge pE; + m_pEnter = NULL; + m_iEnter = -1; + + // test each NON-BV edges + for(int k=0; kpParent->u + pE->pChild->u; + if(iCpParent->u - pE->pChild->u; + if(iC=0) + { + m_pEnter = m_NBVEdges[m_iEnter]; + if(iMinC == (1 - m_pEnter->pChild->u + m_pEnter->pParent->u)) { + // reverse direction + cvPEmdNode pN = m_pEnter->pParent; + m_pEnter->pParent = m_pEnter->pChild; + m_pEnter->pChild = pN; + } + + m_pEnter->iDir = 1; + } + return m_iEnter==-1; +} + +void EmdL1::findNewSolution() +{ + // Find loop formed by adding the Enter BV edge. + findLoopFromEnterBV(); + // Modify flow values along the loop + cvPEmdEdge pE = NULL; + float minFlow = m_pLeave->flow; + int k; + for(k=0; kiDir) pE->flow += minFlow; // outward + else pE->flow -= minFlow; // inward + } + for(k=0; kiDir) pE->flow -= minFlow; // outward + else pE->flow += minFlow; // inward + } + + // Update BV Tree, removing the Leaving-BV edge + cvPEmdNode pLParentN = m_pLeave->pParent; + cvPEmdNode pLChildN = m_pLeave->pChild; + cvPEmdEdge pPreE = pLParentN->pChild; + if(pPreE==m_pLeave) + { + pLParentN->pChild = m_pLeave->pNxt; // Leaving-BV is the first child + } + else + { + while(pPreE->pNxt != m_pLeave) + pPreE = pPreE->pNxt; + pPreE->pNxt = m_pLeave->pNxt; // remove Leaving-BV from child list + } + pLChildN->pParent = NULL; + pLChildN->pPEdge = NULL; + + m_NBVEdges[m_iEnter]= m_pLeave; // put the leaving-BV into the NBV array + + // Add the Enter BV edge + cvPEmdNode pEParentN = m_pEnter->pParent; + cvPEmdNode pEChildN = m_pEnter->pChild; + m_pEnter->flow = minFlow; + m_pEnter->pNxt = pEParentN->pChild; // insert the Enter BV as the first child + pEParentN->pChild = m_pEnter; // of its parent + + // Recursively update the tree start from pEChildN + cvPEmdNode pPreN = pEParentN; + cvPEmdNode pCurN = pEChildN; + cvPEmdNode pNxtN; + cvPEmdEdge pNxtE, pPreE0; + pPreE = m_pEnter; + while(pCurN) + { + pNxtN = pCurN->pParent; + pNxtE = pCurN->pPEdge; + pCurN->pParent = pPreN; + pCurN->pPEdge = pPreE; + if(pNxtN) + { + // remove the edge from pNxtN's child list + if(pNxtN->pChild==pNxtE) + { + pNxtN->pChild = pNxtE->pNxt; // first child + } + else + { + pPreE0 = pNxtN->pChild; + while(pPreE0->pNxt != pNxtE) + pPreE0 = pPreE0->pNxt; + pPreE0->pNxt = pNxtE->pNxt; // remove Leaving-BV from child list + } + // reverse the parent-child direction + pNxtE->pParent = pCurN; + pNxtE->pChild = pNxtN; + pNxtE->iDir = !pNxtE->iDir; + pNxtE->pNxt = pCurN->pChild; + pCurN->pChild = pNxtE; + pPreE = pNxtE; + pPreN = pCurN; + } + pCurN = pNxtN; + } + + // Update U at the child of the Enter BV + pEChildN->u = m_pEnter->iDir?(pEParentN->u-1):(pEParentN->u + 1); + pEChildN->iLevel = pEParentN->iLevel+1; +} + +void EmdL1::findLoopFromEnterBV() +{ + // Initialize Leaving-BV edge + float minFlow = VHIGH; + cvPEmdEdge pE = NULL; + int iLFlag = 0; // 0: in the FROM list, 1: in the TO list + + // Using two loop list to store the loop nodes + cvPEmdNode pFrom = m_pEnter->pParent; + cvPEmdNode pTo = m_pEnter->pChild; + m_iFrom = 0; + m_iTo = 0; + m_pLeave = NULL; + + // Trace back to make pFrom and pTo at the same level + while(pFrom->iLevel > pTo->iLevel) + { + pE = pFrom->pPEdge; + m_fromLoop[m_iFrom++] = pE; + if(!pE->iDir && pE->flowflow; + m_pLeave = pE; + iLFlag = 0; // 0: in the FROM list + } + pFrom = pFrom->pParent; + } + + while(pTo->iLevel > pFrom->iLevel) + { + pE = pTo->pPEdge; + m_toLoop[m_iTo++] = pE; + if(pE->iDir && pE->flowflow; + m_pLeave = pE; + iLFlag = 1; // 1: in the TO list + } + pTo = pTo->pParent; + } + + // Trace pTo and pFrom simultaneously till find their common ancester + while(pTo!=pFrom) + { + pE = pFrom->pPEdge; + m_fromLoop[m_iFrom++] = pE; + if(!pE->iDir && pE->flowflow; + m_pLeave = pE; + iLFlag = 0; // 0: in the FROM list, 1: in the TO list + } + pFrom = pFrom->pParent; + + pE = pTo->pPEdge; + m_toLoop[m_iTo++] = pE; + if(pE->iDir && pE->flowflow; + m_pLeave = pE; + iLFlag = 1; // 0: in the FROM list, 1: in the TO list + } + pTo = pTo->pParent; + } + + // Reverse the direction of the Enter BV edge if necessary + if(iLFlag==0) + { + cvPEmdNode pN = m_pEnter->pParent; + m_pEnter->pParent = m_pEnter->pChild; + m_pEnter->pChild = pN; + m_pEnter->iDir = !m_pEnter->iDir; + } +} + +float EmdL1::compuTotalFlow() +{ + // Computing the total flow as the final distance + float f = 0; + + // Initialize auxiliary queue + m_auxQueue[0] = m_pRoot; + int nQueue = 1; // length of queue + int iQHead = 0; // head of queue + + // BFS browing the tree + cvPEmdNode pCurN=NULL,pNxtN=NULL; + cvPEmdEdge pCurE=NULL; + while(iQHeadpChild; + + // browsing all children + while(pCurE) + { + f += pCurE->flow; + pNxtN = pCurE->pChild; + pCurE = pCurE->pNxt; + m_auxQueue[nQueue++] = pNxtN; + } + } + return f; +} + +/****************************************************************************************\ +* EMDL1 Function * +\****************************************************************************************/ + +float cv::EMDL1(InputArray _signature1, InputArray _signature2) +{ + Mat signature1 = _signature1.getMat(), signature2 = _signature2.getMat(); + EmdL1 emdl1; + return emdl1.getEMDL1(signature1, signature2); +} + diff --git a/modules/shape/src/emdL1_def.hpp b/modules/shape/src/emdL1_def.hpp new file mode 100644 index 0000000000..fae473344b --- /dev/null +++ b/modules/shape/src/emdL1_def.hpp @@ -0,0 +1,142 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 +#include +#include + +#define VHIGH 1e10; +/****************************************************************************************\ +* For EMDL1 Framework * +\****************************************************************************************/ +typedef struct cvEMDEdge* cvPEmdEdge; +typedef struct cvEMDNode* cvPEmdNode; +struct cvEMDNode +{ + int pos[3]; // grid position + float d; // initial value + int u; + // tree maintainance + int iLevel; // level in the tree, 0 means root + cvPEmdNode pParent; // pointer to its parent + cvPEmdEdge pChild; + cvPEmdEdge pPEdge; // point to the edge coming out from its parent +}; +struct cvEMDEdge +{ + float flow; // initial value + int iDir; // 1:outward, 0:inward + // tree maintainance + cvPEmdNode pParent; // point to its parent + cvPEmdNode pChild; // the child node + cvPEmdEdge pNxt; // next child/edge +}; +typedef std::vector cvEMDNodeArray; +typedef std::vector cvEMDEdgeArray; +typedef std::vector cvEMDNodeArray2D; +typedef std::vector cvEMDEdgeArray2D; +typedef std::vector floatArray; +typedef std::vector floatArray2D; + +/****************************************************************************************\ +* EMDL1 Class * +\****************************************************************************************/ +class EmdL1 +{ +public: + EmdL1() + { + m_pRoot = NULL; + binsDim1 = 0; + binsDim2 = 0; + binsDim3 = 0; + dimension = 0; + nMaxIt = 500; + } + + ~EmdL1() + { + } + + float getEMDL1(cv::Mat &sig1, cv::Mat &sig2); + void setMaxIteration(int _nMaxIt); + +private: + //-- SubFunctions called in the EMD algorithm + bool initBaseTrees(int n1=0, int n2=0, int n3=0); + bool fillBaseTrees(float *H1, float *H2); + bool greedySolution(); + bool greedySolution2(); + bool greedySolution3(); + void initBVTree(); + void updateSubtree(cvPEmdNode pRoot); + bool isOptimal(); + void findNewSolution(); + void findLoopFromEnterBV(); + float compuTotalFlow(); + +private: + int dimension; + int binsDim1, binsDim2, binsDim3; // the hitogram contains m_n1 rows and m_n2 columns + int nNBV; // number of Non-Basic Variables (NBV) + int nMaxIt; + cvEMDNodeArray2D m_Nodes; // all nodes + cvEMDEdgeArray2D m_EdgesRight; // all edges to right + cvEMDEdgeArray2D m_EdgesUp; // all edges to upward + std::vector m_3dNodes; // all nodes for 3D + std::vector m_3dEdgesRight; // all edges to right, 3D + std::vector m_3dEdgesUp; // all edges to upward, 3D + std::vector m_3dEdgesDeep; // all edges to deep, 3D + std::vector m_NBVEdges; // pointers to all NON-BV edges + std::vector m_auxQueue; // auxiliary node queue + cvPEmdNode m_pRoot; // root of the BV Tree + cvPEmdEdge m_pEnter; // Enter BV edge + int m_iEnter; // Enter BV edge, index in m_NBVEdges + cvPEmdEdge m_pLeave; // Leave BV edge + int m_nItr; // number of iteration + // auxiliary variables for searching a new loop + std::vector m_fromLoop; + std::vector m_toLoop; + int m_iFrom; + int m_iTo; +}; + diff --git a/modules/shape/src/haus_dis.cpp b/modules/shape/src/haus_dis.cpp new file mode 100644 index 0000000000..5e16a699cc --- /dev/null +++ b/modules/shape/src/haus_dis.cpp @@ -0,0 +1,151 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "precomp.hpp" + +namespace cv +{ + +class HausdorffDistanceExtractorImpl : public HausdorffDistanceExtractor +{ +public: + /* Constructor */ + HausdorffDistanceExtractorImpl(int _distanceFlag = NORM_L1, float _rankProportion=0.6) + { + distanceFlag = _distanceFlag; + rankProportion = _rankProportion; + name_ = "ShapeDistanceExtractor.HAU"; + } + + /* Destructor */ + ~HausdorffDistanceExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual float computeDistance(InputArray contour1, InputArray contour2); + + //! Setters/Getters + virtual void setDistanceFlag(int _distanceFlag) {distanceFlag=_distanceFlag;} + virtual int getDistanceFlag() const {return distanceFlag;} + + virtual void setRankProportion(float _rankProportion) + { + CV_Assert((_rankProportion>0) & (_rankProportion<=1)); + rankProportion=_rankProportion; + } + virtual float getRankProportion() const {return rankProportion;} + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "distance" << distanceFlag + << "rank" << rankProportion; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + distanceFlag = (int)fn["distance"]; + rankProportion = (int)fn["rank"]; + } + +private: + int distanceFlag; + float rankProportion; + +protected: + String name_; +}; + +//! Hausdorff distance for a pair of set of points +static float _apply(const Mat &set1, const Mat &set2, int distType, double propRank) +{ + // Building distance matrix // + Mat disMat(set1.cols, set2.cols, CV_32F); + int K = int(propRank*(disMat.rows-1)); + + for (int r=0; r(0,r)-set2.at(0,c); + disMat.at(r,c) = norm(Mat(diff), distType); + } + } + + Mat shortest(disMat.rows,1,CV_32F); + for (int ii=0; ii(ii,0) = float(mindis); + } + Mat sorted; + cv::sort(shortest, sorted, SORT_EVERY_ROW | SORT_DESCENDING); + return sorted.at(K,0); +} + +float HausdorffDistanceExtractorImpl::computeDistance(InputArray contour1, InputArray contour2) +{ + Mat set1=contour1.getMat(), set2=contour2.getMat(); + if (set1.type() != CV_32F) + set1.convertTo(set1, CV_32F); + if (set2.type() != CV_32F) + set2.convertTo(set2, CV_32F); + CV_Assert((set1.channels()==2) & (set1.cols>0)); + CV_Assert((set2.channels()==2) & (set2.cols>0)); + return std::max( _apply(set1, set2, distanceFlag, rankProportion), + _apply(set2, set1, distanceFlag, rankProportion) ); +} + +Ptr createHausdorffDistanceExtractor(int distanceFlag, float rankProp) +{ + return Ptr(new HausdorffDistanceExtractorImpl(distanceFlag, rankProp)); +} + +} // cv + + diff --git a/modules/shape/src/hist_cost.cpp b/modules/shape/src/hist_cost.cpp new file mode 100644 index 0000000000..67e4063e6b --- /dev/null +++ b/modules/shape/src/hist_cost.cpp @@ -0,0 +1,547 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "precomp.hpp" + +namespace cv +{ + +/*! */ +class NormHistogramCostExtractorImpl : public NormHistogramCostExtractor +{ +public: + /* Constructors */ + NormHistogramCostExtractorImpl(int _flag, int _nDummies, float _defaultCost) + { + flag=_flag; + nDummies=_nDummies; + defaultCost=_defaultCost; + name_ = "HistogramCostExtractor.NOR"; + } + + /* Destructor */ + ~NormHistogramCostExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix); + + //! Setters/Getters + void setNDummies(int _nDummies) + { + nDummies=_nDummies; + } + + int getNDummies() const + { + return nDummies; + } + + void setDefaultCost(float _defaultCost) + { + defaultCost=_defaultCost; + } + + float getDefaultCost() const + { + return defaultCost; + } + + virtual void setNormFlag(int _flag) + { + flag=_flag; + } + + virtual int getNormFlag() const + { + return flag; + } + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "flag" << flag + << "dummies" << nDummies + << "default" << defaultCost; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + flag = (int)fn["flag"]; + nDummies = (int)fn["dummies"]; + defaultCost = (float)fn["default"]; + } + +private: + int flag; + int nDummies; + float defaultCost; + +protected: + String name_; +}; + +void NormHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix) +{ + // size of the costMatrix with dummies // + Mat descriptors1=_descriptors1.getMat(); + Mat descriptors2=_descriptors2.getMat(); + int costrows = std::max(descriptors1.rows, descriptors2.rows)+nDummies; + _costMatrix.create(costrows, costrows, CV_32F); + Mat costMatrix=_costMatrix.getMat(); + + + // Obtain copies of the descriptors // + cv::Mat scd1 = descriptors1.clone(); + cv::Mat scd2 = descriptors2.clone(); + + // row normalization // + for(int i=0; i(i,j)=norm(columnDiff, flag); + } + else + { + costMatrix.at(i,j)=defaultCost; + } + } + } +} + +Ptr createNormHistogramCostExtractor(int flag, int nDummies, float defaultCost) +{ + return Ptr ( new NormHistogramCostExtractorImpl(flag, nDummies, defaultCost) ); +} + +/*! */ +class EMDHistogramCostExtractorImpl : public EMDHistogramCostExtractor +{ +public: + /* Constructors */ + EMDHistogramCostExtractorImpl(int _flag, int _nDummies, float _defaultCost) + { + flag=_flag; + nDummies=_nDummies; + defaultCost=_defaultCost; + name_ = "HistogramCostExtractor.EMD"; + } + + /* Destructor */ + ~EMDHistogramCostExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix); + + //! Setters/Getters + void setNDummies(int _nDummies) + { + nDummies=_nDummies; + } + + int getNDummies() const + { + return nDummies; + } + + void setDefaultCost(float _defaultCost) + { + defaultCost=_defaultCost; + } + + float getDefaultCost() const + { + return defaultCost; + } + + virtual void setNormFlag(int _flag) + { + flag=_flag; + } + + virtual int getNormFlag() const + { + return flag; + } + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "flag" << flag + << "dummies" << nDummies + << "default" << defaultCost; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + flag = (int)fn["flag"]; + nDummies = (int)fn["dummies"]; + defaultCost = (float)fn["default"]; + } + +private: + int flag; + int nDummies; + float defaultCost; + +protected: + String name_; +}; + +void EMDHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix) +{ + // size of the costMatrix with dummies // + Mat descriptors1=_descriptors1.getMat(); + Mat descriptors2=_descriptors2.getMat(); + int costrows = std::max(descriptors1.rows, descriptors2.rows)+nDummies; + _costMatrix.create(costrows, costrows, CV_32F); + Mat costMatrix=_costMatrix.getMat(); + + // Obtain copies of the descriptors // + cv::Mat scd1=descriptors1.clone(); + cv::Mat scd2=descriptors2.clone(); + + // row normalization // + for(int i=0; i(k,1)=k; + } + for (int k=0; k(k,1)=k; + } + + costMatrix.at(i,j) = cv::EMD(sig1, sig2, flag); + } + else + { + costMatrix.at(i,j) = defaultCost; + } + } + } +} + +Ptr createEMDHistogramCostExtractor(int flag, int nDummies, float defaultCost) +{ + return Ptr ( new EMDHistogramCostExtractorImpl(flag, nDummies, defaultCost) ); +} + +/*! */ +class ChiHistogramCostExtractorImpl : public ChiHistogramCostExtractor +{ +public: + /* Constructors */ + ChiHistogramCostExtractorImpl(int _nDummies, float _defaultCost) + { + name_ = "HistogramCostExtractor.CHI"; + nDummies=_nDummies; + defaultCost=_defaultCost; + } + + /* Destructor */ + ~ChiHistogramCostExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix); + + //! setters / getters + void setNDummies(int _nDummies) + { + nDummies=_nDummies; + } + + int getNDummies() const + { + return nDummies; + } + + void setDefaultCost(float _defaultCost) + { + defaultCost=_defaultCost; + } + + float getDefaultCost() const + { + return defaultCost; + } + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "dummies" << nDummies + << "default" << defaultCost; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + nDummies = (int)fn["dummies"]; + defaultCost = (float)fn["default"]; + } + +protected: + String name_; + int nDummies; + float defaultCost; +}; + +void ChiHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix) +{ + // size of the costMatrix with dummies // + Mat descriptors1=_descriptors1.getMat(); + Mat descriptors2=_descriptors2.getMat(); + int costrows = std::max(descriptors1.rows, descriptors2.rows)+nDummies; + _costMatrix.create(costrows, costrows, CV_32FC1); + Mat costMatrix=_costMatrix.getMat(); + + // Obtain copies of the descriptors // + cv::Mat scd1=descriptors1.clone(); + cv::Mat scd2=descriptors2.clone(); + + // row normalization // + for(int i=0; i(i,k)-scd2.at(j,k); + float suma=scd1.at(i,k)+scd2.at(j,k); + csum += resta*resta/(FLT_EPSILON+suma); + } + costMatrix.at(i,j)=csum/2; + } + else + { + costMatrix.at(i,j)=defaultCost; + } + } + } +} + +Ptr createChiHistogramCostExtractor(int nDummies, float defaultCost) +{ + return Ptr ( new ChiHistogramCostExtractorImpl(nDummies, defaultCost) ); +} + +/*! */ +class EMDL1HistogramCostExtractorImpl : public EMDL1HistogramCostExtractor +{ +public: + /* Constructors */ + EMDL1HistogramCostExtractorImpl(int _nDummies, float _defaultCost) + { + name_ = "HistogramCostExtractor.CHI"; + nDummies=_nDummies; + defaultCost=_defaultCost; + } + + /* Destructor */ + ~EMDL1HistogramCostExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual void buildCostMatrix(InputArray descriptors1, InputArray descriptors2, OutputArray costMatrix); + + //! setters / getters + void setNDummies(int _nDummies) + { + nDummies=_nDummies; + } + + int getNDummies() const + { + return nDummies; + } + + void setDefaultCost(float _defaultCost) + { + defaultCost=_defaultCost; + } + + float getDefaultCost() const + { + return defaultCost; + } + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "dummies" << nDummies + << "default" << defaultCost; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + nDummies = (int)fn["dummies"]; + defaultCost = (float)fn["default"]; + } + +protected: + String name_; + int nDummies; + float defaultCost; +}; + +void EMDL1HistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix) +{ + // size of the costMatrix with dummies // + Mat descriptors1=_descriptors1.getMat(); + Mat descriptors2=_descriptors2.getMat(); + int costrows = std::max(descriptors1.rows, descriptors2.rows)+nDummies; + _costMatrix.create(costrows, costrows, CV_32F); + Mat costMatrix=_costMatrix.getMat(); + + // Obtain copies of the descriptors // + cv::Mat scd1=descriptors1.clone(); + cv::Mat scd2=descriptors2.clone(); + + // row normalization // + for(int i=0; i(i,j) = cv::EMDL1(sig1, sig2); + } + else + { + costMatrix.at(i,j) = defaultCost; + } + } + } +} + +Ptr createEMDL1HistogramCostExtractor(int nDummies, float defaultCost) +{ + return Ptr ( new EMDL1HistogramCostExtractorImpl(nDummies, defaultCost) ); +} + +} // cv + + diff --git a/modules/shape/src/precomp.cpp b/modules/shape/src/precomp.cpp new file mode 100644 index 0000000000..730edbb63d --- /dev/null +++ b/modules/shape/src/precomp.cpp @@ -0,0 +1,45 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "precomp.hpp" + +/* End of file. */ diff --git a/modules/shape/src/precomp.hpp b/modules/shape/src/precomp.hpp new file mode 100644 index 0000000000..bc00e5993d --- /dev/null +++ b/modules/shape/src/precomp.hpp @@ -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. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#include +#include +#include + +#include "opencv2/video/tracking.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/shape.hpp" + +#include "opencv2/core/utility.hpp" +#include "opencv2/core/private.hpp" + +#include "opencv2/opencv_modules.hpp" + +#endif diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp new file mode 100644 index 0000000000..98edc56b1f --- /dev/null +++ b/modules/shape/src/sc_dis.cpp @@ -0,0 +1,848 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* + * Implementation of the paper Shape Matching and Object Recognition Using Shape Contexts + * Belongie et al., 2002 by Juan Manuel Perez for GSoC 2013. + */ +#include "precomp.hpp" +//#include "opencv2/highgui.hpp" +/* + * ShapeContextDescriptor class + */ +class SCD +{ +public: + //! the full constructor taking all the necessary parameters + explicit SCD(int _nAngularBins=12, int _nRadialBins=5, + double _innerRadius=0.1, double _outerRadius=1, bool _rotationInvariant=false) + { + setAngularBins(_nAngularBins); + setRadialBins(_nRadialBins); + setInnerRadius(_innerRadius); + setOuterRadius(_outerRadius); + setRotationInvariant(_rotationInvariant); + } + + void extractSCD(cv::Mat& contour, cv::Mat& descriptors, + const std::vector& queryInliers=std::vector(), + const float _meanDistance=-1) + { + cv::Mat contourMat = contour; + cv::Mat disMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + cv::Mat angleMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + + std::vector logspaces, angspaces; + logarithmicSpaces(logspaces); + angularSpaces(angspaces); + buildNormalizedDistanceMatrix(contourMat, disMatrix, queryInliers, _meanDistance); + buildAngleMatrix(contourMat, angleMatrix); + + // Now, build the descriptor matrix (each row is a point) // + descriptors = cv::Mat::zeros(contourMat.cols, descriptorSize(), CV_32F); + + for (int ptidx=0; ptidx0) + { + if (queryInliers[ptidx]==0 || queryInliers[cmp]==0) continue; //avoid outliers + } + + int angidx=-1, radidx=-1; + for (int i=0; i(ptidx, cmp)(ptidx, cmp)(ptidx, idx)++; + } + } + } + } + + int descriptorSize() {return nAngularBins*nRadialBins;} + void setAngularBins(int angularBins) { nAngularBins=angularBins; } + void setRadialBins(int radialBins) { nRadialBins=radialBins; } + void setInnerRadius(double _innerRadius) { innerRadius=_innerRadius; } + void setOuterRadius(double _outerRadius) { outerRadius=_outerRadius; } + void setRotationInvariant(bool _rotationInvariant) { rotationInvariant=_rotationInvariant; } + int getAngularBins() const { return nAngularBins; } + int getRadialBins() const { return nRadialBins; } + double getInnerRadius() const { return innerRadius; } + double getOuterRadius() const { return outerRadius; } + bool getRotationInvariant() const { return rotationInvariant; } + float getMeanDistance() const { return meanDistance; } + +private: + int nAngularBins; + int nRadialBins; + double innerRadius; + double outerRadius; + bool rotationInvariant; + float meanDistance; + +protected: + void logarithmicSpaces(std::vector& vecSpaces) const + { + double logmin=log10(innerRadius); + double logmax=log10(outerRadius); + double delta=(logmax-logmin)/(nRadialBins-1); + double accdelta=0; + + for (int i=0; i& vecSpaces) const + { + double delta=2*CV_PI/nAngularBins; + double val=0; + + for (int i=0; i &queryInliers, + const float _meanDistance=-1) + { + cv::Mat contourMat = contour; + cv::Mat mask(disMatrix.rows, disMatrix.cols, CV_8U); + + for (int i=0; i(i,j) = norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); + if (_meanDistance<0) + { + if (queryInliers.size()>0) + { + mask.at(i,j)=char(queryInliers[j] & queryInliers[i]); + } + else + { + mask.at(i,j)=1; + } + } + } + } + + if (_meanDistance<0) + { + meanDistance=mean(disMatrix, mask)[0]; + } + else + { + meanDistance=_meanDistance; + } + disMatrix/=meanDistance+FLT_EPSILON; + } + + void buildAngleMatrix(cv::Mat& contour, + cv::Mat& angleMatrix) const + { + cv::Mat contourMat = contour; + + // if descriptor is rotationInvariant compute massCenter // + cv::Point2f massCenter(0,0); + if (rotationInvariant) + { + for (int i=0; i(0,i); + } + massCenter.x=massCenter.x/(float)contourMat.cols; + massCenter.y=massCenter.y/(float)contourMat.cols; + } + + + for (int i=0; i(i,j)=0.0; + } + else + { + cv::Point2f dif = contourMat.at(0,i) - contourMat.at(0,j); + angleMatrix.at(i,j) = std::atan2(dif.y, dif.x); + + if (rotationInvariant) + { + cv::Point2f refPt = contourMat.at(0,i) - massCenter; + float refAngle = atan2(refPt.y, refPt.x); + angleMatrix.at(i,j) -= refAngle; + } + angleMatrix.at(i,j) = fmod(angleMatrix.at(i,j)+FLT_EPSILON,2*CV_PI)+CV_PI; + //angleMatrix.at(i,j) = 1+floor( angleMatrix.at(i,j)*nAngularBins/(2*CV_PI) ); + } + } + } + } +}; + +/* + * Matcher + */ +class SCDMatcher +{ +public: + // the full constructor + SCDMatcher() + { + } + + // the matcher function using Hungarian method + void matchDescriptors(cv::Mat& descriptors1, cv::Mat& descriptors2, std::vector& matches, cv::Ptr& comparer, + std::vector& inliers1, std::vector &inliers2) + { + matches.clear(); + + // Build the cost Matrix between descriptors // + cv::Mat costMat; + buildCostMatrix(descriptors1, descriptors2, costMat, comparer); + + // Solve the matching problem using the hungarian method // + hungarian(costMat, matches, inliers1, inliers2, descriptors1.rows, descriptors2.rows); + } + + // matching cost + float getMatchingCost() const {return minMatchCost;} + +private: + float minMatchCost; + float betaAdditional; +protected: + void buildCostMatrix(const cv::Mat& descriptors1, const cv::Mat& descriptors2, + cv::Mat& costMatrix, cv::Ptr& comparer) const + { + comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix); + } + + void hungarian(cv::Mat& costMatrix, std::vector& outMatches, std::vector &inliers1, + std::vector &inliers2, int sizeScd1=0, int sizeScd2=0) + { + std::vector free(costMatrix.rows, 0), collist(costMatrix.rows, 0); + std::vector matches(costMatrix.rows, 0), colsol(costMatrix.rows), rowsol(costMatrix.rows); + std::vector d(costMatrix.rows), pred(costMatrix.rows), v(costMatrix.rows); + + const float LOWV=1e-10; + bool unassignedfound; + int i=0, imin=0, numfree=0, prvnumfree=0, f=0, i0=0, k=0, freerow=0; + int j=0, j1=0, j2=0, endofpath=0, last=0, low=0, up=0; + float min=0, h=0, umin=0, usubmin=0, v2=0; + + // COLUMN REDUCTION // + for (j = costMatrix.rows-1; j >= 0; j--) + { + // find minimum cost over rows. + min = costMatrix.at(0,j); + imin = 0; + for (i = 1; i < costMatrix.rows; i++) + if (costMatrix.at(i,j) < min) + { + min = costMatrix.at(i,j); + imin = i; + } + v[j] = min; + + if (++matches[imin] == 1) + { + rowsol[imin] = j; + colsol[j] = imin; + } + else + { + colsol[j]=-1; + } + } + + // REDUCTION TRANSFER // + for (i=0; i::max(); + for (j=0; j(i,j)-v[j] < min) + { + min=costMatrix.at(i,j)-v[j]; + } + } + } + v[j1] = v[j1]-min; + } + } + } + // AUGMENTING ROW REDUCTION // + int loopcnt = 0; + do + { + loopcnt++; + k=0; + prvnumfree=numfree; + numfree=0; + while (k < prvnumfree) + { + i=free[k]; + k++; + umin = costMatrix.at(i,0)-v[0]; + j1=0; + usubmin = std::numeric_limits::max(); + for (j=1; j(i,j)-v[j]; + if (h < usubmin) + { + if (h >= umin) + { + usubmin = h; + j2 = j; + } + else + { + usubmin = umin; + umin = h; + j2 = j1; + j1 = j; + } + } + } + i0 = colsol[j1]; + + if (fabs(umin-usubmin) > LOWV) //if( umin < usubmin ) + { + v[j1] = v[j1] - (usubmin - umin); + } + else // minimum and subminimum equal. + { + if (i0 >= 0) // minimum column j1 is assigned. + { + j1 = j2; + i0 = colsol[j2]; + } + } + // (re-)assign i to j1, possibly de-assigning an i0. + rowsol[i]=j1; + colsol[j1]=i; + + if (i0 >= 0) + { + //if( umin < usubmin ) + if (fabs(umin-usubmin) > LOWV) + { + free[--k] = i0; + } + else + { + free[numfree++] = i0; + } + } + } + }while (loopcnt<2); // repeat once. + + // AUGMENT SOLUTION for each free row // + for (f = 0; f(freerow,j) - v[j]; + pred[j] = freerow; + collist[j] = j; // init column list. + } + + low=0; // columns in 0..low-1 are ready, now none. + up=0; // columns in low..up-1 are to be scanned for current minimum, now none. + unassignedfound = false; + do + { + if (up == low) + { + last=low-1; + min = d[collist[up++]]; + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + h = d[j]; + if (h <= min) + { + if (h < min) // new minimum. + { + up = low; // restart list at index low. + min = h; + } + collist[k] = collist[up]; + collist[up++] = j; + } + } + for (k=low; k(i,j1)-v[j1]-min; + + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + v2 = costMatrix.at(i,j) - v[j] - h; + if (v2 < d[j]) + { + pred[j] = i; + if (v2 == min) + { + if (colsol[j] < 0) + { + // if unassigned, shortest augmenting path is complete. + endofpath = j; + unassignedfound = true; + break; + } + else + { + collist[k] = collist[up]; + collist[up++] = j; + } + } + d[j] = v2; + } + } + } + }while (!unassignedfound); + + // update column prices. + for (k = 0; k <= last; k++) + { + j1 = collist[k]; + v[j1] = v[j1] + d[j1] - min; + } + + // reset row and column assignments along the alternating path. + do + { + i = pred[endofpath]; + colsol[endofpath] = i; + j1 = endofpath; + endofpath = rowsol[i]; + rowsol[i] = j1; + }while (i != freerow); + } + + // calculate symmetric shape context cost + cv::Mat trueCostMatrix(costMatrix, cv::Rect(0,0,sizeScd1, sizeScd2)); + float leftcost = 0; + for (int nrow=0; nrow(colsol[i],i));//queryIdx,trainIdx,distance + outMatches.push_back(singleMatch); + } + + // Update inliers + inliers1.reserve(sizeScd1); + for (size_t kc = 0; kc &_comparer, const Ptr &_transformer) + { + nAngularBins=_nAngularBins; + nRadialBins=_nRadialBins; + innerRadius=_innerRadius; + outerRadius=_outerRadius; + rotationInvariant=false; + comparer=_comparer; + iterations=_iterations; + transformer=_transformer; + bendingEnergyWeight=0.3; + imageAppearanceWeight=0.0; + shapeContextWeight=1.0; + sigma=10; + name_ = "ShapeDistanceExtractor.SCD"; + } + + /* Destructor */ + ~ShapeContextDistanceExtractorImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operator + virtual float computeDistance(InputArray contour1, InputArray contour2); + + //! Setters/Getters + virtual void setAngularBins(int _nAngularBins){CV_Assert(_nAngularBins>0); nAngularBins=_nAngularBins;} + virtual int getAngularBins() const {return nAngularBins;} + + virtual void setRadialBins(int _nRadialBins){CV_Assert(_nRadialBins>0); nRadialBins=_nRadialBins;} + virtual int getRadialBins() const {return nRadialBins;} + + virtual void setInnerRadius(float _innerRadius) {CV_Assert(_innerRadius>0); innerRadius=_innerRadius;} + virtual float getInnerRadius() const {return innerRadius;} + + virtual void setOuterRadius(float _outerRadius) {CV_Assert(_outerRadius>0); outerRadius=_outerRadius;} + virtual float getOuterRadius() const {return outerRadius;} + + virtual void setRotationInvariant(bool _rotationInvariant) {rotationInvariant=_rotationInvariant;} + virtual bool getRotationInvariant() const {return rotationInvariant;} + + virtual void setCostExtractor(Ptr _comparer) { comparer = _comparer; } + virtual Ptr getCostExtractor() const { return comparer; } + + virtual void setShapeContextWeight(float _shapeContextWeight) {shapeContextWeight=_shapeContextWeight;} + virtual float getShapeContextWeight() const {return shapeContextWeight;} + + virtual void setImageAppearanceWeight(float _imageAppearanceWeight) {imageAppearanceWeight=_imageAppearanceWeight;} + virtual float getImageAppearanceWeight() const {return imageAppearanceWeight;} + + virtual void setBendingEnergyWeight(float _bendingEnergyWeight) {bendingEnergyWeight=_bendingEnergyWeight;} + virtual float getBendingEnergyWeight() const {return bendingEnergyWeight;} + + virtual void setStdDev(float _sigma) {sigma=_sigma;} + virtual float getStdDev() const {return sigma;} + + virtual void setImages(InputArray _image1, InputArray _image2) + { + Mat image1_=_image1.getMat(), image2_=_image2.getMat(); + CV_Assert((image1_.depth()==0) & (image2_.depth()==0)); + image1=image1_; + image2=image2_; + } + + virtual void getImages(OutputArray _image1, OutputArray _image2) const + { + CV_Assert((!image1.empty()) & (!image2.empty())); + _image1.create(image1.size(), image1.type()); + _image2.create(image2.size(), image2.type()); + _image1.getMat()=image1; + _image2.getMat()=image2; + } + + virtual void setIterations(int _iterations) {CV_Assert(_iterations>0); iterations=_iterations;} + virtual int getIterations() const {return iterations;} + + virtual void setTransformAlgorithm(Ptr _transformer) {transformer=_transformer;} + virtual Ptr getTransformAlgorithm() const {return transformer;} + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "nRads" << nRadialBins + << "nAngs" << nAngularBins + << "iters" << iterations + << "img_1" << image1 + << "img_2" << image2 + << "beWei" << bendingEnergyWeight + << "scWei" << shapeContextWeight + << "iaWei" << imageAppearanceWeight + << "costF" << costFlag + << "rotIn" << rotationInvariant + << "sigma" << sigma; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + nRadialBins = (int)fn["nRads"]; + nAngularBins = (int)fn["nAngs"]; + iterations = (int)fn["iters"]; + bendingEnergyWeight = (float)fn["beWei"]; + shapeContextWeight = (float)fn["scWei"]; + imageAppearanceWeight = (float)fn["iaWei"]; + costFlag = (int)fn["costF"]; + sigma = (float)fn["sigma"]; + } + +private: + int nAngularBins; + int nRadialBins; + float innerRadius; + float outerRadius; + bool rotationInvariant; + int costFlag; + int iterations; + Ptr transformer; + Ptr comparer; + Mat image1; + Mat image2; + float bendingEnergyWeight; + float imageAppearanceWeight; + float shapeContextWeight; + float sigma; + +protected: + String name_; +}; + +float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, InputArray contour2) +{ + // Checking // + Mat sset1=contour1.getMat(), sset2=contour2.getMat(), set1, set2; + if (set1.type() != CV_32F) + sset1.convertTo(set1, CV_32F); + else + sset1.copyTo(set1); + + if (set2.type() != CV_32F) + sset2.convertTo(set2, CV_32F); + else + sset1.copyTo(set2); + + CV_Assert((set1.channels()==2) & (set1.cols>0)); + CV_Assert((set2.channels()==2) & (set2.cols>0)); + if (imageAppearanceWeight!=0) + { + CV_Assert((!image1.empty()) & (!image2.empty())); + } + + // Initializing Extractor, Descriptor structures and Matcher // + SCD set1SCE(nAngularBins, nRadialBins, innerRadius, outerRadius, false); + Mat set1SCD; + SCD set2SCE(nAngularBins, nRadialBins, innerRadius, outerRadius, false); + Mat set2SCD; + SCDMatcher matcher; + std::vector matches; + + // Distance components (The output is a linear combination of these 3) // + float sDistance=0, bEnergy=0, iAppearance=0; + float beta; + + // Initializing some variables // + std::vector inliers1, inliers2; + bool isTPS=false; + if ( dynamic_cast(&*transformer) ) + isTPS=true; + Mat warpedImage; + for (int ii=0; ii(&*transformer)->setRegularizationParameter(beta); + transformer->estimateTransformation(set1, set2, matches); + bEnergy += transformer->applyTransformation(set1, set1); + + // Image appearance // + if (imageAppearanceWeight!=0) + { + // Have to accumulate the transformation along all the iterations + if (ii==0) + { + if ( isTPS ) + { + image2.copyTo(warpedImage); + } + else + { + image1.copyTo(warpedImage); + } + } + transformer->warpImage(warpedImage, warpedImage); + } + } + + Mat gaussWindow, diffIm; + if (imageAppearanceWeight!=0) + { + // compute appearance cost + if ( isTPS ) + { + resize(warpedImage, warpedImage, image1.size()); + Mat temp=(warpedImage-image1); + multiply(temp, temp, diffIm); + } + else + { + resize(warpedImage, warpedImage, image2.size()); + Mat temp=(warpedImage-image2); + multiply(temp, temp, diffIm); + } + gaussWindow = Mat::zeros(warpedImage.rows, warpedImage.cols, CV_32F); + for (int pt=0; pt(0,pt).x; + float yy = sset1.at(0,pt).y; + float val = std::exp( -( (xx-jj)*(xx-jj) + (yy-ii)*(yy-ii) )/(2*sigma*sigma) ) / (sigma*sigma*2*CV_PI); + gaussWindow.at(ii,jj) += val; + } + } + } + + Mat appIm(diffIm.rows, diffIm.cols, CV_32F); + for (int ii=0; ii(ii,jj) )/255; + float elemb=gaussWindow.at(ii,jj); + appIm.at(ii,jj) = elema*elemb; + } + } + iAppearance = cv::sum(appIm)[0]/sset1.cols; + } + sDistance = matcher.getMatchingCost(); + + return (sDistance*shapeContextWeight+bEnergy*bendingEnergyWeight+iAppearance*imageAppearanceWeight); +} + +Ptr createShapeContextDistanceExtractor(int nAngularBins, int nRadialBins, float innerRadius, float outerRadius, int iterations, + const Ptr &comparer, const Ptr &transformer) +{ + return Ptr ( new ShapeContextDistanceExtractorImpl(nAngularBins, nRadialBins, innerRadius, + outerRadius, iterations, comparer, transformer) ); +} + +} // cv diff --git a/modules/shape/src/tps_trans.cpp b/modules/shape/src/tps_trans.cpp new file mode 100644 index 0000000000..dd839d670c --- /dev/null +++ b/modules/shape/src/tps_trans.cpp @@ -0,0 +1,288 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "precomp.hpp" + +namespace cv +{ + +class ThinPlateSplineShapeTransformerImpl : public ThinPlateSplineShapeTransformer +{ +public: + /* Constructors */ + ThinPlateSplineShapeTransformerImpl() + { + regularizationParameter=0; + name_ = "ShapeTransformer.TPS"; + tpsComputed=false; + } + + ThinPlateSplineShapeTransformerImpl(double _regularizationParameter) + { + regularizationParameter=_regularizationParameter; + name_ = "ShapeTransformer.TPS"; + tpsComputed=false; + } + + /* Destructor */ + ~ThinPlateSplineShapeTransformerImpl() + { + } + + virtual AlgorithmInfo* info() const { return 0; } + + //! the main operators + virtual void estimateTransformation(InputArray transformingShape, InputArray targetShape, std::vector &matches); + virtual float applyTransformation(InputArray inPts, OutputArray output=noArray()); + virtual void warpImage(InputArray transformingImage, OutputArray output, + int flags, int borderMode, const Scalar& borderValue) const; + + //! Setters/Getters + virtual void setRegularizationParameter(double _regularizationParameter) {regularizationParameter=_regularizationParameter;} + virtual double getRegularizationParameter() const {return regularizationParameter;} + + //! write/read + virtual void write(FileStorage& fs) const + { + fs << "name" << name_ + << "regularization" << regularizationParameter; + } + + virtual void read(const FileNode& fn) + { + CV_Assert( (String)fn["name"] == name_ ); + regularizationParameter = (int)fn["regularization"]; + } + +private: + bool tpsComputed; + double regularizationParameter; + float transformCost; + Mat tpsParameters; + Mat shapeReference; + +protected: + String name_; +}; + +static double distance(Point2f p, Point2f q) +{ + Point2f diff = p - q; + float norma = diff.x*diff.x + diff.y*diff.y;// - 2*diff.x*diff.y; + if (norma<0) norma=0; + //else norma = std::sqrt(norma); + norma = norma*std::log(norma+FLT_EPSILON); + return norma; +} + +static Point2f _applyTransformation(const Mat &shapeRef, const Point2f point, const Mat &tpsParameters) +{ + Point2f out; + for (int i=0; i<2; i++) + { + float a1=tpsParameters.at(tpsParameters.rows-3,i); + float ax=tpsParameters.at(tpsParameters.rows-2,i); + float ay=tpsParameters.at(tpsParameters.rows-1,i); + + float affine=a1+ax*point.x+ay*point.y; + float nonrigid=0; + for (int j=0; j(j,i)* + distance(Point2f(shapeRef.at(j,0),shapeRef.at(j,1)), + point); + } + if (i==0) + { + out.x=affine+nonrigid; + } + if (i==1) + { + out.y=affine+nonrigid; + } + } + return out; +} + +/* public methods */ +void ThinPlateSplineShapeTransformerImpl::warpImage(InputArray transformingImage, OutputArray output, + int flags, int borderMode, const Scalar& borderValue) const +{ + CV_Assert(tpsComputed==true); + + Mat theinput = transformingImage.getMat(); + Mat mapX(theinput.rows, theinput.cols, CV_32FC1); + Mat mapY(theinput.rows, theinput.cols, CV_32FC1); + + for (int row = 0; row < theinput.rows; row++) + { + for (int col = 0; col < theinput.cols; col++) + { + Point2f pt = _applyTransformation(shapeReference, Point2f(float(col), float(row)), tpsParameters); + mapX.at(row, col) = pt.x; + mapY.at(row, col) = pt.y; + } + } + remap(transformingImage, output, mapX, mapY, flags, borderMode, borderValue); +} + +float ThinPlateSplineShapeTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts) +{ + CV_Assert(tpsComputed); + Mat pts1 = inPts.getMat(); + CV_Assert((pts1.channels()==2) & (pts1.cols>0)); + + //Apply transformation in the complete set of points + // Ensambling output // + if (outPts.needed()) + { + outPts.create(1,pts1.cols, CV_32FC2); + Mat outMat = outPts.getMat(); + for (int i=0; i(0,i); + outMat.at(0,i)=_applyTransformation(shapeReference, pt, tpsParameters); + } + } + + return transformCost; +} + +void ThinPlateSplineShapeTransformerImpl::estimateTransformation(InputArray _pts1, InputArray _pts2, + std::vector& _matches ) +{ + Mat pts1 = _pts1.getMat(); + Mat pts2 = _pts2.getMat(); + CV_Assert((pts1.channels()==2) & (pts1.cols>0) & (pts2.channels()==2) & (pts2.cols>0)); + CV_Assert(_matches.size()>1); + + if (pts1.type() != CV_32F) + pts1.convertTo(pts1, CV_32F); + if (pts2.type() != CV_32F) + pts2.convertTo(pts2, CV_32F); + + // Use only valid matchings // + std::vector matches; + for (size_t i=0; i<_matches.size(); i++) + { + if (_matches[i].queryIdx(0,matches[i].queryIdx); + shape1.at(i,0) = pt1.x; + shape1.at(i,1) = pt1.y; + + Point2f pt2=pts2.at(0,matches[i].trainIdx); + shape2.at(i,0) = pt2.x; + shape2.at(i,1) = pt2.y; + } + shape1.copyTo(shapeReference); + + // Building the matrices for solving the L*(w|a)=(v|0) problem with L={[K|P];[P'|0]} + + //Building K and P (Neede to buil L) + Mat matK(matches.size(),matches.size(),CV_32F); + Mat matP(matches.size(),3,CV_32F); + for (size_t i=0; i(i,j)=regularizationParameter; + } + else + { + matK.at(i,j) = distance(Point2f(shape1.at(i,0),shape1.at(i,1)), + Point2f(shape1.at(j,0),shape1.at(j,1))); + } + } + matP.at(i,0) = 1; + matP.at(i,1) = shape1.at(i,0); + matP.at(i,2) = shape1.at(i,1); + } + + //Building L + Mat matL=Mat::zeros(matches.size()+3,matches.size()+3,CV_32F); + Mat matLroi(matL, Rect(0,0,matches.size(),matches.size())); //roi for K + matK.copyTo(matLroi); + matLroi = Mat(matL,Rect(matches.size(),0,3,matches.size())); //roi for P + matP.copyTo(matLroi); + Mat matPt; + transpose(matP,matPt); + matLroi = Mat(matL,Rect(0,matches.size(),matches.size(),3)); //roi for P' + matPt.copyTo(matLroi); + + //Building B (v|0) + Mat matB = Mat::zeros(matches.size()+3,2,CV_32F); + for (size_t i=0; i(i,0) = shape2.at(i,0); //x's + matB.at(i,1) = shape2.at(i,1); //y's + } + + //Obtaining transformation params (w|a) + solve(matL, matB, tpsParameters, DECOMP_LU); + //tpsParameters = matL.inv()*matB; + + //Setting transform Cost and Shape reference + Mat w(tpsParameters, Rect(0,0,2,tpsParameters.rows-3)); + Mat Q=w.t()*matK*w; + transformCost=fabs(Q.at(0,0)*Q.at(1,1));//fabs(mean(Q.diag(0))[0]);//std::max(Q.at(0,0),Q.at(1,1)); + tpsComputed=true; +} + +Ptr createThinPlateSplineShapeTransformer(double regularizationParameter) +{ + return Ptr( new ThinPlateSplineShapeTransformerImpl(regularizationParameter) ); +} + +} // cv diff --git a/modules/shape/test/test_emdl1.cpp b/modules/shape/test/test_emdl1.cpp new file mode 100644 index 0000000000..1f7aba545c --- /dev/null +++ b/modules/shape/test/test_emdl1.cpp @@ -0,0 +1,266 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "test_precomp.hpp" + +using namespace cv; +using namespace std; + +const int angularBins=12; +const int radialBins=4; +const float minRad=0.2; +const float maxRad=2; +const int NSN=5;//10;//20; //number of shapes per class +const int NP=100; //number of points sympliying the contour +const float outlierWeight=0.1; +const int numOutliers=20; +const float CURRENT_MAX_ACCUR=95; //98% and 99% reached in several tests, 95 is fixed as minimum boundary + +class CV_ShapeEMDTest : public cvtest::BaseTest +{ +public: + CV_ShapeEMDTest(); + ~CV_ShapeEMDTest(); +protected: + void run(int); + +private: + void mpegTest(); + void listShapeNames(vector &listHeaders); + vector convertContourType(const Mat &, int n=0 ); + float computeShapeDistance(vector & queryNormal, + vector & queryFlipped1, + vector & queryFlipped2, + vector& testq); + void displayMPEGResults(); +}; + +CV_ShapeEMDTest::CV_ShapeEMDTest() +{ +} +CV_ShapeEMDTest::~CV_ShapeEMDTest() +{ +} + +vector CV_ShapeEMDTest::convertContourType(const Mat& currentQuery, int n) +{ + vector > _contoursQuery; + vector contoursQuery; + findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); + for (size_t border=0; border<_contoursQuery.size(); border++) + { + for (size_t p=0; p<_contoursQuery[border].size(); p++) + { + contoursQuery.push_back(Point2f((float)_contoursQuery[border][p].x, + (float)_contoursQuery[border][p].y)); + } + } + + // In case actual number of points is less than n + int dum=0; + for (int add=contoursQuery.size()-1; add cont; + for (int i=0; i &listHeaders) +{ + listHeaders.push_back("apple"); //ok + listHeaders.push_back("children"); // ok + listHeaders.push_back("device7"); // ok + listHeaders.push_back("Heart"); // ok + listHeaders.push_back("teddy"); // ok +} +float CV_ShapeEMDTest::computeShapeDistance(vector & query1, vector & query2, + vector & query3, vector & testq) +{ + //waitKey(0); + Ptr mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); + //Ptr cost = createNormHistogramCostExtractor(cv::DIST_L1); + //Ptr cost = createChiHistogramCostExtractor(30,0.15); + //Ptr cost = createEMDHistogramCostExtractor(); + // Ptr cost = createEMDL1HistogramCostExtractor(); + mysc->setIterations(1); //(3) + mysc->setCostExtractor( createEMDL1HistogramCostExtractor() ); + //mysc->setTransformAlgorithm(createAffineTransformer(true)); + mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); + //mysc->setImageAppearanceWeight(1.6); + //mysc->setImageAppearanceWeight(0.0); + //mysc->setImages(im1,imtest); + return ( std::min( mysc->computeDistance(query1, testq), + std::min(mysc->computeDistance(query2, testq), mysc->computeDistance(query3, testq) ))); +} + +void CV_ShapeEMDTest::mpegTest() +{ + string baseTestFolder="shape/mpeg_test/"; + string path = cvtest::TS::ptr()->get_data_path() + baseTestFolder; + vector namesHeaders; + listShapeNames(namesHeaders); + + // distance matrix // + Mat distanceMat=Mat::zeros(NSN*namesHeaders.size(), NSN*namesHeaders.size(), CV_32F); + + // query contours (normal v flipped, h flipped) and testing contour // + vector contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting; + + // reading query and computing its properties // + int counter=0; + const int loops=NSN*namesHeaders.size()*NSN*namesHeaders.size(); + for (size_t n=0; n origContour; + contoursQuery1=convertContourType(currentQuery, NP); + origContour=contoursQuery1; + contoursQuery2=convertContourType(flippedHQuery, NP); + contoursQuery3=convertContourType(flippedVQuery, NP); + + // compare with all the rest of the images: testing // + for (size_t nt=0; nt(NSN*n+i-1, + NSN*nt+it-1)=0; + continue; + } + // read testing image // + stringstream thetestpathandname; + thetestpathandname<(NSN*n+i-1, NSN*nt+it-1)= + computeShapeDistance(contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting); + std::cout<(NSN*n+i-1, NSN*nt+it-1)<get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::WRITE); + fs << "distanceMat" << distanceMat; +} + +const int FIRST_MANY=2*NSN; +void CV_ShapeEMDTest::displayMPEGResults() +{ + string baseTestFolder="shape/mpeg_test/"; + Mat distanceMat; + FileStorage fs(cvtest::TS::ptr()->get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::READ); + vector namesHeaders; + listShapeNames(namesHeaders); + + // Read generated MAT // + fs["distanceMat"]>>distanceMat; + + int corrects=0; + int divi=0; + for (int row=0; row(row,col)>distanceMat.at(row,i)) + { + nsmall++; + } + } + if (nsmall<=FIRST_MANY) + { + corrects++; + } + } + } + float porc = 100*float(corrects)/(NSN*distanceMat.rows); + std::cout<<"%="<= CURRENT_MAX_ACCUR) + ts->set_failed_test_info(cvtest::TS::OK); + else + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + +} + +void CV_ShapeEMDTest::run( int /*start_from*/ ) +{ + mpegTest(); + displayMPEGResults(); +} + +TEST(ShapeEMD_SCD, regression) { CV_ShapeEMDTest test; test.safe_run(); } diff --git a/modules/shape/test/test_hausdorff.cpp b/modules/shape/test/test_hausdorff.cpp new file mode 100644 index 0000000000..dfff6bcb3c --- /dev/null +++ b/modules/shape/test/test_hausdorff.cpp @@ -0,0 +1,280 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "test_precomp.hpp" +#include + +using namespace cv; +using namespace std; + +const int NSN=5;//10;//20; //number of shapes per class +const float CURRENT_MAX_ACCUR=85; //90% and 91% reached in several tests, 85 is fixed as minimum boundary + +class CV_HaussTest : public cvtest::BaseTest +{ +public: + CV_HaussTest(); + ~CV_HaussTest(); +protected: + void run(int); +private: + float computeShapeDistance(vector &query1, vector &query2, + vector &query3, vector &testq); + vector convertContourType(const Mat& currentQuery, int n=180); + vector normalizeContour(const vector & contour); + void listShapeNames( vector &listHeaders); + void mpegTest(); + void displayMPEGResults(); +}; + +CV_HaussTest::CV_HaussTest() +{ +} +CV_HaussTest::~CV_HaussTest() +{ +} + +vector CV_HaussTest::normalizeContour(const vector &contour) +{ + vector output(contour.size()); + Mat disMat(contour.size(),contour.size(),CV_32F); + Point2f meanpt(0,0); + float meanVal=1; + + for (size_t ii=0; ii(ii,jj)=0; + else + { + disMat.at(ii,jj)= + fabs(contour[ii].x*contour[jj].x)+fabs(contour[ii].y*contour[jj].y); + } + } + meanpt.x+=contour[ii].x; + meanpt.y+=contour[ii].y; + } + meanpt.x/=contour.size(); + meanpt.y/=contour.size(); + meanVal=cv::mean(disMat)[0]; + for (size_t ii=0; ii &listHeaders) +{ + listHeaders.push_back("apple"); //ok + listHeaders.push_back("children"); // ok + listHeaders.push_back("device7"); // ok + listHeaders.push_back("Heart"); // ok + listHeaders.push_back("teddy"); // ok +} + + +vector CV_HaussTest::convertContourType(const Mat& currentQuery, int n) +{ + vector > _contoursQuery; + vector contoursQuery; + findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); + for (size_t border=0; border<_contoursQuery.size(); border++) + { + for (size_t p=0; p<_contoursQuery[border].size(); p++) + { + contoursQuery.push_back(_contoursQuery[border][p]); + } + } + + // In case actual number of points is less than n + for (int add=contoursQuery.size()-1; add cont; + for (int i=0; i& query1, vector & query2, + vector & query3, vector & testq) +{ + Ptr haus = createHausdorffDistanceExtractor(); + return std::min(haus->computeDistance(query1,testq), std::min(haus->computeDistance(query2,testq), + haus->computeDistance(query3,testq))); +} + +void CV_HaussTest::mpegTest() +{ + string baseTestFolder="shape/mpeg_test/"; + string path = cvtest::TS::ptr()->get_data_path() + baseTestFolder; + vector namesHeaders; + listShapeNames(namesHeaders); + + // distance matrix // + Mat distanceMat=Mat::zeros(NSN*namesHeaders.size(), NSN*namesHeaders.size(), CV_32F); + + // query contours (normal v flipped, h flipped) and testing contour // + vector contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting; + + // reading query and computing its properties // + int counter=0; + const int loops=NSN*namesHeaders.size()*NSN*namesHeaders.size(); + for (size_t n=0; n origContour; + contoursQuery1=convertContourType(currentQuery); + origContour=contoursQuery1; + contoursQuery2=convertContourType(flippedHQuery); + contoursQuery3=convertContourType(flippedVQuery); + + // compare with all the rest of the images: testing // + for (size_t nt=0; nt(NSN*n+i-1, + NSN*nt+it-1)=0; + continue; + } + // read testing image // + stringstream thetestpathandname; + thetestpathandname<(NSN*n+i-1, NSN*nt+it-1)= + computeShapeDistance(contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting); + std::cout<(NSN*n+i-1, NSN*nt+it-1)<get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::WRITE); + fs << "distanceMat" << distanceMat; +} + +const int FIRST_MANY=2*NSN; +void CV_HaussTest::displayMPEGResults() +{ + string baseTestFolder="shape/mpeg_test/"; + Mat distanceMat; + FileStorage fs(cvtest::TS::ptr()->get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::READ); + vector namesHeaders; + listShapeNames(namesHeaders); + + // Read generated MAT // + fs["distanceMat"]>>distanceMat; + + int corrects=0; + int divi=0; + for (int row=0; row(row,col)>distanceMat.at(row,i)) + { + nsmall++; + } + } + if (nsmall<=FIRST_MANY) + { + corrects++; + } + } + } + float porc = 100*float(corrects)/(NSN*distanceMat.rows); + std::cout<<"%="<= CURRENT_MAX_ACCUR) + ts->set_failed_test_info(cvtest::TS::OK); + else + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + +} + + +void CV_HaussTest::run(int /* */) +{ + mpegTest(); + displayMPEGResults(); + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Hauss, regression) { CV_HaussTest test; test.safe_run(); } diff --git a/modules/shape/test/test_main.cpp b/modules/shape/test/test_main.cpp new file mode 100644 index 0000000000..6b24993447 --- /dev/null +++ b/modules/shape/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/modules/shape/test/test_precomp.cpp b/modules/shape/test/test_precomp.cpp new file mode 100644 index 0000000000..5956e13e3e --- /dev/null +++ b/modules/shape/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/modules/shape/test/test_precomp.hpp b/modules/shape/test/test_precomp.hpp new file mode 100644 index 0000000000..e73248422b --- /dev/null +++ b/modules/shape/test/test_precomp.hpp @@ -0,0 +1,21 @@ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic ignored "-Wmissing-prototypes" +# pragma GCC diagnostic ignored "-Wextra" +# endif +#endif + +#ifndef __OPENCV_TEST_PRECOMP_HPP__ +#define __OPENCV_TEST_PRECOMP_HPP__ + +#include +#include "opencv2/ts.hpp" +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/shape.hpp" + +#include "opencv2/opencv_modules.hpp" + +#endif diff --git a/modules/shape/test/test_shape.cpp b/modules/shape/test/test_shape.cpp new file mode 100644 index 0000000000..81d67f6ac1 --- /dev/null +++ b/modules/shape/test/test_shape.cpp @@ -0,0 +1,267 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including 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 "test_precomp.hpp" + +using namespace cv; +using namespace std; + +const int angularBins=12; +const int radialBins=4; +const float minRad=0.2; +const float maxRad=2; +const int NSN=5;//10;//20; //number of shapes per class +const int NP=120; //number of points sympliying the contour +const float outlierWeight=0.1; +const int numOutliers=20; +const float CURRENT_MAX_ACCUR=95.0; //99% and 100% reached in several tests, 95 is fixed as minimum boundary + +class CV_ShapeTest : public cvtest::BaseTest +{ +public: + CV_ShapeTest(); + ~CV_ShapeTest(); +protected: + void run(int); + +private: + void mpegTest(); + void listShapeNames(vector &listHeaders); + vector convertContourType(const Mat &, int n=0 ); + float computeShapeDistance(vector & queryNormal, + vector & queryFlipped1, + vector & queryFlipped2, + vector& testq); + void displayMPEGResults(); +}; + +CV_ShapeTest::CV_ShapeTest() +{ +} +CV_ShapeTest::~CV_ShapeTest() +{ +} + +vector CV_ShapeTest::convertContourType(const Mat& currentQuery, int n) +{ + vector > _contoursQuery; + vector contoursQuery; + findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); + for (size_t border=0; border<_contoursQuery.size(); border++) + { + for (size_t p=0; p<_contoursQuery[border].size(); p++) + { + contoursQuery.push_back(Point2f((float)_contoursQuery[border][p].x, + (float)_contoursQuery[border][p].y)); + } + } + + // In case actual number of points is less than n + for (int add=contoursQuery.size()-1; add cont; + for (int i=0; i &listHeaders) +{ + listHeaders.push_back("apple"); //ok + listHeaders.push_back("children"); // ok + listHeaders.push_back("device7"); // ok + listHeaders.push_back("Heart"); // ok + listHeaders.push_back("teddy"); // ok +} + +float CV_ShapeTest::computeShapeDistance(vector & query1, vector & query2, + vector & query3, vector & testq) +{ + //waitKey(0); + Ptr mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); + //Ptr cost = createNormHistogramCostExtractor(cv::DIST_L1); + Ptr cost = createChiHistogramCostExtractor(30,0.15); + //Ptr cost = createEMDHistogramCostExtractor(); + //Ptr cost = createEMDL1HistogramCostExtractor(); + mysc->setIterations(1); + mysc->setCostExtractor( cost ); + //mysc->setTransformAlgorithm(createAffineTransformer(true)); + mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); + //mysc->setImageAppearanceWeight(1.6); + //mysc->setImageAppearanceWeight(0.0); + //mysc->setImages(im1,imtest); + return ( std::min( mysc->computeDistance(query1, testq), + std::min(mysc->computeDistance(query2, testq), mysc->computeDistance(query3, testq) ))); +} + +void CV_ShapeTest::mpegTest() +{ + string baseTestFolder="shape/mpeg_test/"; + string path = cvtest::TS::ptr()->get_data_path() + baseTestFolder; + vector namesHeaders; + listShapeNames(namesHeaders); + + // distance matrix // + Mat distanceMat=Mat::zeros(NSN*namesHeaders.size(), NSN*namesHeaders.size(), CV_32F); + + // query contours (normal v flipped, h flipped) and testing contour // + vector contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting; + + // reading query and computing its properties // + int counter=0; + const int loops=NSN*namesHeaders.size()*NSN*namesHeaders.size(); + for (size_t n=0; n origContour; + contoursQuery1=convertContourType(currentQuery, NP); + origContour=contoursQuery1; + contoursQuery2=convertContourType(flippedHQuery, NP); + contoursQuery3=convertContourType(flippedVQuery, NP); + + // compare with all the rest of the images: testing // + for (size_t nt=0; nt(NSN*n+i-1, + NSN*nt+it-1)=0; + continue; + } + // read testing image // + stringstream thetestpathandname; + thetestpathandname<(NSN*n+i-1, NSN*nt+it-1)= + computeShapeDistance(contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting); + std::cout<(NSN*n+i-1, NSN*nt+it-1)<get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::WRITE); + fs << "distanceMat" << distanceMat; +} + +const int FIRST_MANY=2*NSN; +void CV_ShapeTest::displayMPEGResults() +{ + string baseTestFolder="shape/mpeg_test/"; + Mat distanceMat; + FileStorage fs(cvtest::TS::ptr()->get_data_path() + baseTestFolder + "distanceMatrixMPEGTest.yml", FileStorage::READ); + vector namesHeaders; + listShapeNames(namesHeaders); + + // Read generated MAT // + fs["distanceMat"]>>distanceMat; + + int corrects=0; + int divi=0; + for (int row=0; row(row,col)>distanceMat.at(row,i)) + { + nsmall++; + } + } + if (nsmall<=FIRST_MANY) + { + corrects++; + } + } + } + float porc = 100*float(corrects)/(NSN*distanceMat.rows); + std::cout<<"%="<= CURRENT_MAX_ACCUR) + ts->set_failed_test_info(cvtest::TS::OK); + else + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); + //done +} + +void CV_ShapeTest::run( int /*start_from*/ ) +{ + mpegTest(); + displayMPEGResults(); + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Shape_SCD, regression) { CV_ShapeTest test; test.safe_run(); } diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 5d38958fc4..c3477e3fb7 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -5,7 +5,7 @@ SET(OPENCV_CPP_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree opencv_softcascade - opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab opencv_bioinspired) + opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab opencv_bioinspired opencv_shape) ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/cpp/shape_example.cpp b/samples/cpp/shape_example.cpp new file mode 100644 index 0000000000..921330e894 --- /dev/null +++ b/samples/cpp/shape_example.cpp @@ -0,0 +1,111 @@ +/* + * shape_context.cpp -- Shape context demo for shape matching + */ + +#include "opencv2/shape.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/imgproc.hpp" +#include +#include +#include + +using namespace std; +using namespace cv; + +static void help() +{ + printf("\n" + "This program demonstrates a method for shape comparisson based on Shape Context\n" + "You should run the program providing a number between 1 and 20 for selecting an image in the folder shape_sample.\n" + "Call\n" + "./shape_example [number between 1 and 20]\n\n"); +} + +static vector simpleContour( const Mat& currentQuery, int n=300 ) +{ + vector > _contoursQuery; + vector contoursQuery; + findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); + for (size_t border=0; border<_contoursQuery.size(); border++) + { + for (size_t p=0; p<_contoursQuery[border].size(); p++) + { + contoursQuery.push_back( _contoursQuery[border][p] ); + } + } + + // In case actual number of points is less than n + int dummy=0; + for (int add=contoursQuery.size()-1; add cont; + for (int i=0; i mysc = cv::createShapeContextDistanceExtractor(); + + Size sz2Sh(300,300); + stringstream queryName; + queryName< contQuery = simpleContour(query); + int bestMatch; + float bestDis=FLT_MAX; + for ( int ii=1; ii<=20; ii++ ) + { + if (ii==indexQuery) continue; + waitKey(30); + stringstream iiname; + iiname< contii = simpleContour(iiIm); + float dis = mysc->computeDistance( contQuery, contii ); + if ( disRW&bd$s-D`QbYy?`Hx`B&7oQ6~=xGu>5X>OM7Q!IRnlx4atR8cO z(^_M;YaiHI7y4@(JZSyG5}?iH@S>F=O|4-rN5h(JafhP#F4X8v;TBf>$ZPtctG}gb zyC|!WA2%19#aRu34}J{4?H(Se5pZ~%{F`|}MuRMOrTJO=2#cc~WuC zoM+X?j%%qA6;qQ&sV?qFn7m)jeTmTG=BJ%ZaK>q!q1*_dCf<$ z>#IIaI~CQ-xgunxP{7I{=D-%lMIAg-vNMA>1TDx>u8qr7WgDk(Boq&%* zKl@Shp65)COs83oK40*#=}~uZutVX&NzH}kC(5(WIqs7T=3^1x!4$zI!IhF7YqNa4 z#uHWb*p;Vh4PsaBWXYUwI^oMpt%TcdU(GBY`7X)5qQ6yay`kozP{%tT&zJSycA91; z&|By=o%_EnN5e1PMa$vf`MsY^i6<2|E6xoB#kg9DYeY$Mer|4RUI{~DK|xNcu8Cej zdM;OTeqLE>QAuiwLV%yILRw}{YKgFyA5e!XNJmOyNvc(HQ7VvPFfuSS)-^EKH8cw` zG_f)=wlXo+HZZa>FwpVqTZ^J0H$Npat&+je($Z4b&`{UVD8$gx3WN-`4Ge)AS}y4C Q0%~CJboFyt=akR{05*IHP5=M^ literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/10.png b/samples/cpp/shape_sample/10.png new file mode 100644 index 0000000000000000000000000000000000000000..46283caacac38a87916a833b1f933f4c83daccfb GIT binary patch literal 1024 zcmV+b1poVqP)s0ALa-lq&QFS|J-~ zm5h)90#FYwQf7pV5*aC6dIcI;KqU)-3`yxpBy~T}u@NMQ*ctpR-W^Yro`g8ZInHs8 zbNpkY_udcqwDf6ADDdkr$h^J+KZ5gWoA-`f09!=mz%dtqF42}?CQ^VCX{vc|sSu$s z>lNxX=@7~wpb&~6!1*i)34^^7EevKl#ymc70Z8vX6fZGlbh0nV;ItJO3 zmOZQ4)1H4`;H4aHd}g7Qx<2*T=O+8)WuM*r(;v%odw)RE*xx|dcNq392+7lMU|?d% z-sNCmIbb-jhrqv1D*sGXAp&#Uul$X*^G0!?BX%N!@d(^YKo0?5fT8zKM4=KGSWuM0 z6hANkFzE{D0(5@r4$lK94hMPx?E%OY^dZTK29FUmdB?0^PM}L5{doj_1y%zfUNg2)1oN_D4eSbj zL~wzCyaE?WN`tVMFqk8FUVx{8(HKy%AG_Fd6=-*$7cgKT%&Azbu?ABD?FxDle2Ku6 zK<%JMfLTG9yZ3Y6);b4G1P?V3N07I51;Rf+#GdQ809k^&8icf_ z9EcKJA{aR^&_GmQ_Kv`CpbR1GaSiIxaX@_Lz`J;&P(b7W{0u8IU?3p69Sk549~PjA z@69U^uLX_+BMwvo_`GN$_(%ZZ#5vA!j{jx+0zGo8Pm|b8SO5S3D0D?wbYpLAZDnqB z0B>V-Z*X;UEjcc5XKe~&Z*F#Fa&%>6AW%+CAZBT7Whv|brvLx|C3HntbYx+4WjbSW zWnpw>05UK!Gc7PTEipD!F*G_dGdeUlD=;!TFfcAj+E)Mo03~!qSaf7zbY(hiZ)9m^ uc>pmvIXNvcF)cANR53X^F*!OjGb=DLIxsL%YB}xz0000EamTaeV7F@4mwdJPa3HB2!KZT5!25@7@`fXC%|8s_gnPA^AYS zjBU!ID>Z7BYI+vNPJ4b-CVBhw8xJ?{Yn1=Rw@^K6#fk8bm&y{?p1k~d@%uyHXCGn+ zuRN!`tCPK`;=}G8nKE6`4`&x-{7s2x>?Ph#=m;1=W?y;81vn}bsKgs+pGJoc=;QPiIZ)@t`<(7+AmVzSsJ5XBkHHk zY1q}ceBYF;^KqT`Lax?+e60Wd;>0!29nDH)=TDk_&bD?^@Er4qC9eP|~&T}?jEta~##(h6{-2)M>%eOAwG#1zM+`)EAp|(4(;Hz4!Y~{Nci`Ie} z`Y)d!`hJb?{-wL8zTaW<<+PsPv-NBAb77uZOSN;yFP6>8m-@Wu`Rt(5dFzw!?wr44 z_7BUCkI#NPAG7!6UA8OS*Y`b}xx4qH@cD-?kK5Y6d3UpBS83>V;qb?W9~t@%UEcL0 z_S*U#KY|m~-b(NP|NhtEb!v9q{+lO$IzO>wKM(tl!b95&&5eZIAE%~lFFDFrrI~zv z=YOV2J5Q;l{_>RvM!Q;xYeY$Mer|4RUI{~TQGR)zu9;pzdM;OTeqLE>QAuiwLV%yI zLRw}{YA5pwEuaonkdBnZl2ohYqEsNoU}RuutZQJdYiJf?Xkuk#Y-MVoZD3?&U~rLV z$~qJcx%nxXX_X9ymX?;fhK9O^Mj?ilR$!!UUUftDnm{r-UW|vaCMJ literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/12.png b/samples/cpp/shape_sample/12.png new file mode 100644 index 0000000000000000000000000000000000000000..ad876e9397aa8377d57d89cd842a94b106a49ea4 GIT binary patch literal 437 zcmeAS@N?(olHy`uVBq!ia0vp^@jz_K2qYNzBe+t46jPG7y9)!us$OLyAdj=aBeEDs zdw{Xq$!t3yLV~EE2wU?~<4lD4mCAjnS$TTi4Fu75+R*qFuJVCp;^|idZU{L#( zpqZZ<;};10t^c`8;S1};^)ogpgm^Wti1cBfvs9JMre29(frmMG&w|88@f~R&o-%M9 zS+1s`^y|ngR*&8-u1k5IY%(khVm#rSk)rM^BeFF>R8!m~<$0%_qU-?`wlizn9cGt{ zpJGUMd)t&Rxuku{H_pPQhjDG}?*yJiNZg)#;Bc<`v&Zunus#-7VP2nM-f_S6uGohA z$JcIf==sLxlOz0QPIJg?poi2-Tq8=7^K)}k^GXc z6axHw71AXxff^V*UHx3vIVCg! E0Q--T;Q#;t literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/13.png b/samples/cpp/shape_sample/13.png new file mode 100644 index 0000000000000000000000000000000000000000..2ec2621b2ef090b30e95d45fca00879a31737598 GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0y~yVA2C&MxX%02E%jc?PRtcka5D(#WAGf*4v8*IU5WFTn~zJZ&s?_#5Mb45@*?h2fiN_8YfIRb9i-g zeeVPn&q+}9GH=Fp-KUXpXJ%e&JeXiGqhsT$^#@bZ|9p7UBb=T-=SJ?GW4U*h*<5~- z+hcS}V{wnxe^WQf)G2{r;;Mmf->;mieVhJQur>pAOYpFfO}*@$2zJt|P24?4FK*GC zvDOjjC(RPqh?3;|+}zZ>5{8u2vdrXE3tb}vy@K>yuH^i@vecrI)D(pPKVOBk%$!t* z|MS~`np8oWQW8s2t&)pUffR$0fuXUkfw``sS%{&Dm65TPiJ7*6k(Gf#UD-lVs3SDw w=BH$)RWcY_T3YHF8tNJvg&0~|0g;ihwt*o~!`uUw1wai9p00i_>zopr0E~T>(f|Me literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/14.png b/samples/cpp/shape_sample/14.png new file mode 100644 index 0000000000000000000000000000000000000000..956e5b8145e37cfcb7066c30e96e1b399ef7018d GIT binary patch literal 1820 zcmZXVc~H{_7RLh&v|vz_>j%YxBH@sP-!I`vf=12=m_P(nU_p+M0CI$qh*S^}mJlEc zX%qqy4Oir*6kL=;Wy2MS7DZ*DMk-aHV#*>Qa!J$uYj<|$edjap&3yiQ^Iks1_qeu} zu@(#l)AsiA@Q1-vQGZ26Ie`5LJxEbPHR{B14;ZZBsySNOX(oFGGnMrEPl(cZ0t}{M z?d{g7=~TqZoxe>YwFq}clEtV#+vNTll(uP5FT!1JbnCu z=WL1?5f{BmhjvK9sSWUM8QLP7cV02@7DI1err^plZdSctpXex>B#&&yUYUF;#kb7a z^~P7~&})}Yb5`Q=p>v6Ahse1-wvgxZBOBWd79&D!YH4(X9?N? z19^7I=o=&B`rFLL1@{IiCNJ+;aN^GxN1Wt&F3MNy@jj+yVT;46YJj*Fdn(VS^oFgo zI5eW+j!#8-4e!S4ofhPH7jGMLx5*EFI_-g9fC z`b(%*%<<_?>dL(z;?liJ+{n&Oy7lj!C#1tm?W^v{w~CrGDLjJTZs(yM`|+dcmYJ{A z6e+6HZ}Al_HNofBE6aV&>e@^1M$~L;Y z`S-`<@}@zspik{&SY{HKA?Stfaa)M-g#2StA}4{-%!OeO{Ov}b**Y@1L z(A6^urz>))ofy?|;|b0tsL9R;x&7d^CreRuA(e4S5IhH%(#~dOa$%4)`zb)j2i`Z; zr3&WJ+*K+fcbOA;(2tHDsk)5ast2&kbUn6FbJgHZlZz~QeRSLCYUDnd_dptAIflJD*D4aY8tKwM7cZ?}S*E^@ z0Mv~Z5AgR2zD85j*l3EZg5!p%Q7Hw8Spq#tEL@ig`dd`Md~( zIi&i`VLuguC%Qj{IuzuG@)0i|C;yH?(ZZ}v8Mpsynb-cciRT~HAY;iP0KrB-=M{k5 zC^{rUX=r2X3S605qm{%Eoc8S3jNMpH!pj~mI|JtA_uPVd&{xr@Qcu`KF{-PmTm$+%O;%fI6!^-5J#XcwEV z9d%Hal>?l=N(u@yp$dKzKOPh4jT>K0Bm90dsia1KU55UP^=1*AIuUp1&bxv*O5o7Z`H@^yG z!ypY28LC=%0@sQXMsm# zF_88EW4Dvpc0d)To-U3d8Ta1a^zB=0Ai$cSEEZS9()TF)Y}SW6XD-FGC|8_hddSzP zlIr~EyMu4P+dAE!OkbIe+*S&ydQH&?T;$T3->ud%QAMrgfklyU;sO_2;diHI&15;f zOvuT<T*hFJ)6F6n#%He=|q;-sV*Dh$^K_+4DbN(dEWWB^J(Xzla0%tHl`Q-d1B7-Q9-bKg`9Hpj*NCe{l3T^i;Zdl z5*xXHZq7XY`|8o6HQ^RBrzMxIJJ>OCXZ2a0vuPjyw7sa-URAi)s==o2%j<1ge&;ss z4=8z+{6_Hi%onnY{;>w-yXLvho3P*ezn$ABy|n!Q6RQcnq%+r-6f3FS6uxsy&VbEt6zxsYb z%M?D9MSsOq7M)rkpxV5BLA>f=^IbQkv;)&jstcuJY^)B~Y&OXGcK)2f{K~AnLoO#} z9IyS+b&lG0tbJdErrGbWrz{M`8@%?pbb=!N$HgB^GY_bn-%7l71elUkN?apKlJj$O zQ}ap~vQsN{&GZV=bGef9^U6|-N>Wo40{nax(lT>W|9&WU0;*R9sZU8PNwrEYN(E93 zMh1q)x(4RDhGrp#CRRqqRwm}!21Zr}1~(X2?L*O!o1c=IR>@#!X=$lzXsByw6k=#; d1w_V%+6IO|4adG}90zJ(@O1TaS?83{1OPfVOK|`I literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/16.png b/samples/cpp/shape_sample/16.png new file mode 100644 index 0000000000000000000000000000000000000000..57ad4104a67291baaf605bf3a66cba2b7424c094 GIT binary patch literal 830 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 KMNUMnLSTYsFV-;t literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/2.png b/samples/cpp/shape_sample/2.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7c31b9426545d24a0c3ae83562edaf85f3ede5 GIT binary patch literal 813 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5!6ZWo=hV|c9#fLHy9)!us$OLyAdj=aBeEDs zdw{Xq$!t5I3R_PX$B>MBZ*KRsmHt9I9>f5-yC!GjZ4cewKU88 z`0nL<*)8tp(^EeW+&-Oo`Oagx?>mn7ORQy2_#4Bv_r6pxQ}cHYH{)psT@utblrUV& z)0+0uoJrp`Vej|S18*L19*kkQ%U37-BbZ6IF^#>x`+(pL^T+XmUs%2=%9$!|4dWcqr>$`x#)9SU=}Tm)Y2;aK$b1BWSF zWGkObK$f3Tmbb(C%sPe_j$LyMJY+l8E>JLhIXU_x$A#@qb1Y;#?rzh%!O`*f!hGgO z7CcuEtW5al^FW{dt>=asnUZ+6G^U4FO~M&#^6i9ga?ajqU<*Yk6jHu3>SS+jr^&!~a5qkmh|-5vQaYExFY!f)cF-pZJ|| zO8Cvnu4HpKP?CeqYt{LNS8sWin{Af-QD^@_w%LBlkLz>fo{BWcrT%DoaC_0LDSPrC z^@_gVQ;~hF+Wh{VtqN|OQ>-4pWBew+p}Emk;N7AnsXc}sr!2~fHi);}Re9rH=+0f8 zbR+ceKAG}w8_YZIy1w&IY8S3vawqku-P`($)xXlu+P*9NSi!2${Vnj9{-SJPic%|a zjVMXZ&&^HED`7}1D9B0GwbUy}&*e(a&nrtUDoIUI2=Mb&NXyJg^|S5m0P0W$=}1W| zNwrEYN(E93Mh1q)x(4RDhGrp#CRRqqRwl;U21Zr}20DIyYf&`h=BH$)RWcY_T3YHF j8tNJvg&0~|fsmoLfgw;s%LV;iKn)C@u6{1-oD!M<(78rw literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/20.png b/samples/cpp/shape_sample/20.png new file mode 100644 index 0000000000000000000000000000000000000000..de8d5ed3e2cf10397a512d87ec5bfa9236e95747 GIT binary patch literal 1571 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 literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/6.png b/samples/cpp/shape_sample/6.png new file mode 100644 index 0000000000000000000000000000000000000000..e87cf4d2c45dfc9c6b98c939722ebe225a03ffa2 GIT binary patch literal 969 zcmV;)12+7LP)0)+V zV-}UTSS5Tkj^ZOQJESsrAce#>#{Q`?6IJ3#-Be$&-}AGL5+Tkw z!N%H-IBBiz2`naP2`p#W0$9z^uv}O+vm@EaD+DDkj=>RDhZJ&wItvwrHHDupzlL&w z2Ii87io$Av9ZWh8o1-w>XZC4O9)`IVe=h862zABa@Y!j3Xc!dJt}4+9Urwh0pnf=P9|%i!k{*WLGoYeZyP`MtK?pjxqE~xGFXE%HrO;$y z4R6C0=9i{s$NdfFE56>u+4`(7Tb~tX>x17G4&Uwht7Z)hb7>!kxwI|J=Jpbh%f^8% zg&l<>h3QUnp`oy+&|=t9m?}`=!jZyMfqd9eI8bOYG!%9ejuh?}D1?T>fkKO6OJPUh zK;d42q=jQ|;XvWe*b!(b>?s^6+?k}MkBq?hddJ{EVYEbX7-`EU4*yIu^&eZ?{b(ul zDw>4u;8hBC6uSMP=o6FBQ0Qh|rl4ELA_aR2-8Pab=(TVP+AqO|)(69y!iqvglS!>% zPocNHQfuh;V{#4sBO?L*<0@5gd<3|4Oct`G(5p|XkY0TrQb-K_I|svt!kR)wVWN;; z*4wm;_yfbV`}?fJE6h(@-zO8o%5|eNned+V(jJ_ThR|z^-YG-~y|j&!UlM9(+M9QQ zAeY-`H?Rq&xHiBBI&HBoS{bXOTOaLCXY;P))W=%|6G9Q@viwhPU>#2JI!xrX<~GUJ zZGr8`_er)Q6PsN2Ld6?!cWje|0#0!mn|w_x?O32+@8qJ literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/7.png b/samples/cpp/shape_sample/7.png new file mode 100644 index 0000000000000000000000000000000000000000..b12aa52d2bebfbbf6235bc66e586a54bf2f7df3c GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0y~yV4MJC-(>_640}r@(}5IIlDE4H1H-CbWg{Suv%n*= z7)X17vD?XPJD`eUPZ!6KjC*fy+7_)b5MW8rU~=kPu=qvBqYRl=WdWgpYpb`%UErS; z_8Ds*+&+NiC+JS_JYCwvH(onc_NN>b2n#^IMY@?(;!Uw=|PL$9Gjb!MIV;T*>tPUvPtV^#iq|s4l>bQ<;#k&bpR}c?*;TEH*f>%{w5; zZuId;P0Nk_UU%e`uiLVTs~_C{Y1hxk(Uo`qs5j-jiSRqL<pzwHl#S_F&9GpBi{)u>5{nL|&z8igR`G0u(=aipE)+YUD zG&Hzb=di4N($xP}pO`GwJ?~6Rn^$5|`Oy0lfm zw%f#Jv@&Ji389WzpXB^f-fj3d-C@^`Cwco0nNGFaCAs(Kd;TT;SAw4^^yl6eQhHZE z=fW%j&CL@gp8sE}JRw8Ctlma1Kdnkl*5R3-uBy(;JC#a&Y8UzDF8OA5phb~KVdkNk zUlb%4pKnO{uw6Rw?a~1GwR4Ypi1Xf7%hsRHEuGp>TKVslrPulEaXB`2)9wFVbD0-c z8=v=*vGM6k$MuIUeQ7wbN#m7x#7apon>LnxHhZ#Cn5$I|l->s?n7Wn!82t?@_!j(_ zUj$5tx+Sg=CCT}@xv6<23l_m4Sht=dExQ y4Y~O#nQ4^_hL)C=x`u|jhDITVmR3MyY@%&o2-Gm;EPDb_1B0ilpUXO@geCx+-fK+& literal 0 HcmV?d00001 diff --git a/samples/cpp/shape_sample/8.png b/samples/cpp/shape_sample/8.png new file mode 100644 index 0000000000000000000000000000000000000000..52fff13d41f67f7859caf61b526f02909b09adf1 GIT binary patch literal 851 zcmeAS@N?(olHy`uVBq!ia0y~yV4MJCUt|Ol45zl=lmSvqN#5=*3=FG!m5qQr&H|6f zVj%4S#%?FG?SLv`JY5_^GVZ;-={sq$0T1hg0G)_m9Cls(X?@26EttH;R#s@u^-B_d z`7(3HtXDHPUHeChjhfweA5ZCyd3PY;)M6)xQ9mDRcY-MPg@8Yv0Q_W|| z)iZfb$CdcfK21)VYOdcHF_%MSXXn-34x488v{(pOuj4<|@yI^>g0nET^0&6AgZsD#RS&^{jI$i~n;syhSF(w`u-{M$!6&=N{jL!{#V`QMq4US2ZdB z(7HNTChv9W9w{gPg`aq)zIy(dbUpEDF@Kl*S}^6#-ODN8g#W+Y`p;zA-MgDptldw% zyFTA*+W#p}?ESwTe{@Yn^2zVIR|==U_wL(us3-gXzR!;*vZ(C4r_gr%r-zaK^9wbV zj`^OqwXe)oec$rR)$RS%-`!WPtJJvHol}z8C(r!J>O@hdx9Bf@&q(FfUP^LZAyFwW z%3YqOXe%&2R~4JHIEM4=#X=*EBWF$OR;^3kmumgUdvn_M=bCHNIllf-o0s!e)4cgf z)?&84C02^nvF}7*|DUBP^eRz3>BskJ`Mu`t`cK_$S7aS}Fn{6RLmT83wwnGt>5)>i zqVdF!h?~Ea_5#zz)z#ta))WvN9asVNEpe!dE6nK`L{g92^?HL8L%rX-f6S|t~y0x1R~ z14Cn719M$Nvk*fQDnC}Q!>*k84N8gEp-hIbq$R|3@xpI b$k;^Nz!0cm%31aVpaup{S3j3^P6oN9a-NsEaIf1)^TSOBNQC!8RU#2432zYOBX84POm24B))S*uCA`z1`cr{bOx% z&dqc;ccHB$a7WWbzdC_is{JDNJKG$98bn}VI}fNmVobr-2%#Rxko7y$nqqC5`3U(K zyy(wXM3f*MV=6(q?3Ml`S3?b$_7u`d)TWS3qS}up!Rz44#8?MgdyaUP^*N$hDgrF+ zAg(Y53Yc~fR~Uip-~++mu-w02v>&i>rUtle^U4Oe?En#Uzx|+NuzS*W z&+6`J-@h;DRL(cvS!AZpTd#X>c5mM9-QBAnRKaq1qJJ99wq za&=&OK=;5kh5qZLaBr z`2(W@R+Ryj0O{7L0Dk+#+Wg{74cNFrUY(J+9wP7q`TA7u#ccvFCk7nA4;sK8`L+X7 z2Y#+!ef?M(s2z+2;0Ks|kZT*f02pw^9AFDT1`z&P0(StTDgd4dWdvZ`N6djaz;^(T zHNa0`eM;NFuVo!<0N!@s+CVD`2&hL1HJ5?$0%`{{1$>`?TrD|R0~il5HNj^9ItAha z69M!AeBYDXa9Jx11^~}FU?sq1odN%!pP}Y{74R^88;Bhk3fQn-xU3Vv0#G?{6<`x! zFW>@rLM2rNkLa9p2?*;3$wYsc+X`6FrIdrP;(nACkN{R1z#%uqRPr476&LW3jRH>x zI1@3X01D3dX^5BzpLKo!i@+EY5x|xMGaz7gz%CGecP3)21BSr*D*z6~1BeQMh~wsy zC4jKtzCD3X!DC2_fAVtf-8vYq&p=85Kk{=e{9#iC>>-w94WL8L!CjXFe8_p+1b$I` zGD{GP9_nQbHI#z&0$T-KB@2&-w^89^pDadm|!~t zfP|=p0OkO)>}PUg`{V`j4TvxuFz60o>;u4_pON?y<`%FgaAuK)l5D0D?wbYpLAZDnqB0B>V-Z*X;UEjTW4XKe~&Z*F#Fa&%>6AW%+C zAZBT7WvI@YfB*mhC3HntbYx+4WjbSWWnpw>05UK!Gc7PTEipD!F*G_dGdeUlD=;!T zFfcAj+E)Mo03~!qSaf7zbY(hiZ)9m^c>pmvIXNvcF)cANR53X^F*!OjGb=DLIxsL% SYB}xz0000 +#include +#include + +using namespace std; +using namespace cv; + +static void help() +{ + printf("\nThis program demonstrates how to use common interface for shape transformers\n" + "Call\n" + "shape_transformation [image1] [image2]\n"); +} + +int main(int argc, char** argv) +{ + help(); + Mat img1 = imread(argv[1], IMREAD_GRAYSCALE); + Mat img2 = imread(argv[2], IMREAD_GRAYSCALE); + if(img1.empty() || img2.empty() || argc<2) + { + printf("Can't read one of the images\n"); + return -1; + } + + // detecting keypoints + SurfFeatureDetector detector(5000); + vector keypoints1, keypoints2; + detector.detect(img1, keypoints1); + detector.detect(img2, keypoints2); + + // computing descriptors + SurfDescriptorExtractor extractor; + Mat descriptors1, descriptors2; + extractor.compute(img1, keypoints1, descriptors1); + extractor.compute(img2, keypoints2, descriptors2); + + // matching descriptors + BFMatcher matcher(NORM_L2); + vector matches; + matcher.match(descriptors1, descriptors2, matches); + + // drawing the results + namedWindow("matches", 1); + Mat img_matches; + drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); + imshow("matches", img_matches); + + // extract points + vector pts1, pts2; + for (size_t ii=0; ii mytps = createThinPlateSplineShapeTransformer(25000); //TPS with a relaxed constraint + mytps->estimateTransformation(pts1, pts2, matches); + mytps->warpImage(img2, img2); + + imshow("Tranformed", img2); + waitKey(0); + + return 0; +} From fe7bab499fb43625cc59837ada11f19779131aa6 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Mon, 23 Sep 2013 21:24:27 +0200 Subject: [PATCH 02/12] Corrections for compiling issues in Win, And and Doc --- modules/shape/doc/histogram_cost_matrix.rst | 2 +- modules/shape/doc/shape_distances.rst | 6 ++--- modules/shape/include/opencv2/shape/emdL1.hpp | 2 +- modules/shape/src/aff_trans.cpp | 2 +- modules/shape/src/emdL1.cpp | 15 ++++++------- modules/shape/src/emdL1_def.hpp | 1 - modules/shape/src/haus_dis.cpp | 6 ++--- modules/shape/src/hist_cost.cpp | 8 +++---- modules/shape/src/sc_dis.cpp | 22 +++++++++---------- modules/shape/src/tps_trans.cpp | 4 ++-- modules/shape/test/test_hausdorff.cpp | 6 ++--- modules/shape/test/test_shape.cpp | 2 +- samples/cpp/shape_example.cpp | 2 +- samples/cpp/shape_transformation.cpp | 2 +- 14 files changed, 37 insertions(+), 43 deletions(-) diff --git a/modules/shape/doc/histogram_cost_matrix.rst b/modules/shape/doc/histogram_cost_matrix.rst index 9f6804dd0b..8c338dbee7 100644 --- a/modules/shape/doc/histogram_cost_matrix.rst +++ b/modules/shape/doc/histogram_cost_matrix.rst @@ -70,7 +70,7 @@ An Chi based cost extraction. :: CV_EXPORTS_W Ptr createChiHistogramCostExtractor(int nDummies=25, float defaultCost=0.2); EMDL1HistogramCostExtractor -------------------------- +--------------------------- .. ocv:class:: EMDL1HistogramCostExtractor : public HistogramCostExtractor An EMD-L1 based cost extraction. :: diff --git a/modules/shape/doc/shape_distances.rst b/modules/shape/doc/shape_distances.rst index c671e97ed5..6a6ce95329 100644 --- a/modules/shape/doc/shape_distances.rst +++ b/modules/shape/doc/shape_distances.rst @@ -1,11 +1,11 @@ -Shape Distance and Common Interfaces +Shape Distance and Common Interfaces ==================================== .. highlight:: cpp Shape Distance algorithms in OpenCV are derivated from a common interface that allows you to switch between them in a practical way for solving the same problem with different methods. -Thus, all objects that implement shape distance measures inherit the +Thus, all objects that implement shape distance measures inherit the :ocv:class:`ShapeDistanceExtractor` interface. @@ -123,7 +123,7 @@ ShapeContextDistanceExtractor::setShapeContextWeight ---------------------------------------------------- Set the weight of the shape context distance in the final value of the shape distance. The shape context distance between two shapes is defined as the symmetric sum of shape -context matching costs over best matching points. +context matching costs over best matching points. The final value of the shape distance is a user-defined linear combination of the shape context distance, an image appearance distance, and a bending energy. diff --git a/modules/shape/include/opencv2/shape/emdL1.hpp b/modules/shape/include/opencv2/shape/emdL1.hpp index 400d26b261..74c734a519 100644 --- a/modules/shape/include/opencv2/shape/emdL1.hpp +++ b/modules/shape/include/opencv2/shape/emdL1.hpp @@ -55,4 +55,4 @@ CV_EXPORTS float EMDL1(InputArray signature1, InputArray signature2); }//namespace cv -#endif +#endif diff --git a/modules/shape/src/aff_trans.cpp b/modules/shape/src/aff_trans.cpp index c416b82056..e3d41d0ea4 100644 --- a/modules/shape/src/aff_trans.cpp +++ b/modules/shape/src/aff_trans.cpp @@ -88,7 +88,7 @@ public: virtual void read(const FileNode& fn) { CV_Assert( (String)fn["name"] == name_ ); - fullAffine = (int)fn["affine_type"]; + fullAffine = (bool)int(fn["affine_type"]); } private: diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index cdd903e1ab..423f8ef5d6 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -41,11 +41,11 @@ //M*/ /* - * Implementation of an optimized EMD for histograms based in - * the papers "EMD-L1: An efficient and Robust Algorithm - * for comparing histogram-based descriptors", by Haibin Ling and + * Implementation of an optimized EMD for histograms based in + * the papers "EMD-L1: An efficient and Robust Algorithm + * for comparing histogram-based descriptors", by Haibin Ling and * Kazunori Okuda; and "The Earth Mover's Distance is the Mallows - * Distance: Some Insights from Statistics", by Elizaveta Levina and + * Distance: Some Insights from Statistics", by Elizaveta Levina and * Peter Bickel, based on HAIBIN LING AND KAZUNORI OKADA implementation. */ @@ -393,9 +393,9 @@ bool EmdL1::greedySolution3() //- determine which direction to move, either right or upward dFlow = D[i1][i2][i3]; - f1 = i1<(binsDim1-1)?fabs(dFlow+d1s[i1+1]):VHIGH; - f2 = i2<(binsDim2-1)?fabs(dFlow+d2s[i2+1]):VHIGH; - f3 = i3<(binsDim3-1)?fabs(dFlow+d3s[i3+1]):VHIGH; + f1 = i1<(binsDim1-1)?(float)fabs(dFlow+d1s[i1+1]):VHIGH; + f2 = i2<(binsDim2-1)?(float)fabs(dFlow+d2s[i2+1]):VHIGH; + f3 = i3<(binsDim3-1)?(float)fabs(dFlow+d3s[i3+1]):VHIGH; if(f1(0,r)-set2.at(0,c); - disMat.at(r,c) = norm(Mat(diff), distType); + disMat.at(r,c) = (float)norm(Mat(diff), distType); } } @@ -147,5 +147,3 @@ Ptr createHausdorffDistanceExtractor(int distanceFl } } // cv - - diff --git a/modules/shape/src/hist_cost.cpp b/modules/shape/src/hist_cost.cpp index 67e4063e6b..4e18687ad8 100644 --- a/modules/shape/src/hist_cost.cpp +++ b/modules/shape/src/hist_cost.cpp @@ -156,7 +156,7 @@ void NormHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, I if (i(i,j)=norm(columnDiff, flag); + costMatrix.at(i,j)=(float)norm(columnDiff, flag); } else { @@ -288,11 +288,11 @@ void EMDHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, In sig2.col(0)=scd2.row(j).t(); for (int k=0; k(k,1)=k; + sig1.at(k,1)=float(k); } for (int k=0; k(k,1)=k; + sig2.at(k,1)=float(k); } costMatrix.at(i,j) = cv::EMD(sig1, sig2, flag); @@ -543,5 +543,3 @@ Ptr createEMDL1HistogramCostExtractor(int nDummies, flo } } // cv - - diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index 98edc56b1f..e41efc2298 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -42,7 +42,7 @@ /* * Implementation of the paper Shape Matching and Object Recognition Using Shape Contexts - * Belongie et al., 2002 by Juan Manuel Perez for GSoC 2013. + * Belongie et al., 2002 by Juan Manuel Perez for GSoC 2013. */ #include "precomp.hpp" //#include "opencv2/highgui.hpp" @@ -176,7 +176,7 @@ protected: { for (int j=0; j(i,j) = norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); + disMatrix.at(i,j) = (float)norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); if (_meanDistance<0) { if (queryInliers.size()>0) @@ -193,7 +193,7 @@ protected: if (_meanDistance<0) { - meanDistance=mean(disMatrix, mask)[0]; + meanDistance=(float)mean(disMatrix, mask)[0]; } else { @@ -239,7 +239,7 @@ protected: float refAngle = atan2(refPt.y, refPt.x); angleMatrix.at(i,j) -= refAngle; } - angleMatrix.at(i,j) = fmod(angleMatrix.at(i,j)+FLT_EPSILON,2*CV_PI)+CV_PI; + angleMatrix.at(i,j) = float(fmod(double(angleMatrix.at(i,j)+(double)FLT_EPSILON),2*CV_PI)+CV_PI); //angleMatrix.at(i,j) = 1+floor( angleMatrix.at(i,j)*nAngularBins/(2*CV_PI) ); } } @@ -426,7 +426,7 @@ protected: for (j = 0; j < costMatrix.rows; j++) { d[j] = costMatrix.at(freerow,j) - v[j]; - pred[j] = freerow; + pred[j] = float(freerow); collist[j] = j; // init column list. } @@ -479,7 +479,7 @@ protected: v2 = costMatrix.at(i,j) - v[j] - h; if (v2 < d[j]) { - pred[j] = i; + pred[j] = float(i); if (v2 == min) { if (colsol[j] < 0) @@ -511,7 +511,7 @@ protected: // reset row and column assignments along the alternating path. do { - i = pred[endofpath]; + i = int(pred[endofpath]); colsol[endofpath] = i; j1 = endofpath; endofpath = rowsol[i]; @@ -526,7 +526,7 @@ protected: { double minval; minMaxIdx(trueCostMatrix.row(nrow), &minval); - leftcost+=minval; + leftcost+=float(minval); } leftcost /= trueCostMatrix.rows; @@ -535,7 +535,7 @@ protected: { double minval; minMaxIdx(trueCostMatrix.col(ncol), &minval); - rightcost+=minval; + rightcost+=float(minval); } rightcost /= trueCostMatrix.cols; @@ -815,7 +815,7 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In { float xx = sset1.at(0,pt).x; float yy = sset1.at(0,pt).y; - float val = std::exp( -( (xx-jj)*(xx-jj) + (yy-ii)*(yy-ii) )/(2*sigma*sigma) ) / (sigma*sigma*2*CV_PI); + float val = float(std::exp( -float( (xx-jj)*(xx-jj) + (yy-ii)*(yy-ii) )/(2*sigma*sigma) ) / (sigma*sigma*2*CV_PI)); gaussWindow.at(ii,jj) += val; } } @@ -831,7 +831,7 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In appIm.at(ii,jj) = elema*elemb; } } - iAppearance = cv::sum(appIm)[0]/sset1.cols; + iAppearance = float(cv::sum(appIm)[0]/sset1.cols); } sDistance = matcher.getMatchingCost(); diff --git a/modules/shape/src/tps_trans.cpp b/modules/shape/src/tps_trans.cpp index dd839d670c..b841567dca 100644 --- a/modules/shape/src/tps_trans.cpp +++ b/modules/shape/src/tps_trans.cpp @@ -104,7 +104,7 @@ protected: String name_; }; -static double distance(Point2f p, Point2f q) +static float distance(Point2f p, Point2f q) { Point2f diff = p - q; float norma = diff.x*diff.x + diff.y*diff.y;// - 2*diff.x*diff.y; @@ -237,7 +237,7 @@ void ThinPlateSplineShapeTransformerImpl::estimateTransformation(InputArray _pts { if (i==j) { - matK.at(i,j)=regularizationParameter; + matK.at(i,j)=float(regularizationParameter); } else { diff --git a/modules/shape/test/test_hausdorff.cpp b/modules/shape/test/test_hausdorff.cpp index dfff6bcb3c..d1fdf3881a 100644 --- a/modules/shape/test/test_hausdorff.cpp +++ b/modules/shape/test/test_hausdorff.cpp @@ -87,7 +87,7 @@ vector CV_HaussTest::normalizeContour(const vector &contour) else { disMat.at(ii,jj)= - fabs(contour[ii].x*contour[jj].x)+fabs(contour[ii].y*contour[jj].y); + float(fabs(double(contour[ii].x*contour[jj].x)))+float(fabs(double(contour[ii].y*contour[jj].y))); } } meanpt.x+=contour[ii].x; @@ -95,7 +95,7 @@ vector CV_HaussTest::normalizeContour(const vector &contour) } meanpt.x/=contour.size(); meanpt.y/=contour.size(); - meanVal=cv::mean(disMat)[0]; + meanVal=float(cv::mean(disMat)[0]); for (size_t ii=0; iiset_failed_test_info(cvtest::TS::OK); + ts->set_failed_test_info(cvtest::TS::OK); } TEST(Hauss, regression) { CV_HaussTest test; test.safe_run(); } diff --git a/modules/shape/test/test_shape.cpp b/modules/shape/test/test_shape.cpp index 81d67f6ac1..6415420072 100644 --- a/modules/shape/test/test_shape.cpp +++ b/modules/shape/test/test_shape.cpp @@ -81,7 +81,7 @@ CV_ShapeTest::~CV_ShapeTest() } vector CV_ShapeTest::convertContourType(const Mat& currentQuery, int n) -{ +{ vector > _contoursQuery; vector contoursQuery; findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); diff --git a/samples/cpp/shape_example.cpp b/samples/cpp/shape_example.cpp index 921330e894..d723a73e5f 100644 --- a/samples/cpp/shape_example.cpp +++ b/samples/cpp/shape_example.cpp @@ -75,7 +75,7 @@ int main(int argc, char** argv) imshow("QUERY", queryToShow); moveWindow("TEST", 0,0); vector contQuery = simpleContour(query); - int bestMatch; + int bestMatch = 0; float bestDis=FLT_MAX; for ( int ii=1; ii<=20; ii++ ) { diff --git a/samples/cpp/shape_transformation.cpp b/samples/cpp/shape_transformation.cpp index aa83cd7d14..abd7eab7b1 100644 --- a/samples/cpp/shape_transformation.cpp +++ b/samples/cpp/shape_transformation.cpp @@ -48,7 +48,7 @@ int main(int argc, char** argv) BFMatcher matcher(NORM_L2); vector matches; matcher.match(descriptors1, descriptors2, matches); - + // drawing the results namedWindow("matches", 1); Mat img_matches; From ead966709d78127848e452cf5ec242c92c98b082 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Tue, 24 Sep 2013 18:26:19 +0200 Subject: [PATCH 03/12] Remove ~ file --- modules/shape/doc/shape.rst~ | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 modules/shape/doc/shape.rst~ diff --git a/modules/shape/doc/shape.rst~ b/modules/shape/doc/shape.rst~ deleted file mode 100644 index b18968556b..0000000000 --- a/modules/shape/doc/shape.rst~ +++ /dev/null @@ -1,15 +0,0 @@ -***** -shape -***** - -The module contains algorithms that embed a notion of shape distance. -These algorithms may be used for shape matching and retrieval, or shape -comparison. - -.. toctree:: - :maxdepth: 2 - - shape_distances - shape_transformers - histogram_cost_matrix - emdL1 From 5a1e9876fcec863ae454b0f540a01f0ffe127efe Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Tue, 24 Sep 2013 22:21:31 +0200 Subject: [PATCH 04/12] Corrected compilation errors Win --- modules/shape/src/aff_trans.cpp | 4 ++-- modules/shape/src/emdL1.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/shape/src/aff_trans.cpp b/modules/shape/src/aff_trans.cpp index e3d41d0ea4..02f290fec0 100644 --- a/modules/shape/src/aff_trans.cpp +++ b/modules/shape/src/aff_trans.cpp @@ -82,13 +82,13 @@ public: virtual void write(FileStorage& fs) const { fs << "name" << name_ - << "affine_type" << fullAffine; + << "affine_type" << int(fullAffine); } virtual void read(const FileNode& fn) { CV_Assert( (String)fn["name"] == name_ ); - fullAffine = (bool)int(fn["affine_type"]); + fullAffine = int(fn["affine_type"])?true:false; } private: diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index 423f8ef5d6..1c09ae40a8 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -48,7 +48,7 @@ * Distance: Some Insights from Statistics", by Elizaveta Levina and * Peter Bickel, based on HAIBIN LING AND KAZUNORI OKADA implementation. */ - + #include "precomp.hpp" #include "emdL1_def.hpp" @@ -393,9 +393,9 @@ bool EmdL1::greedySolution3() //- determine which direction to move, either right or upward dFlow = D[i1][i2][i3]; - f1 = i1<(binsDim1-1)?(float)fabs(dFlow+d1s[i1+1]):VHIGH; - f2 = i2<(binsDim2-1)?(float)fabs(dFlow+d2s[i2+1]):VHIGH; - f3 = i3<(binsDim3-1)?(float)fabs(dFlow+d3s[i3+1]):VHIGH; + f1 = i1<(binsDim1-1)?(float)fabs(float(dFlow+d1s[i1+1])):VHIGH; + f2 = i2<(binsDim2-1)?(float)fabs(float(dFlow+d2s[i2+1])):VHIGH; + f3 = i3<(binsDim3-1)?(float)fabs(float(dFlow+d3s[i3+1])):VHIGH; if(f1 Date: Tue, 24 Sep 2013 23:05:29 +0200 Subject: [PATCH 05/12] Compile error fix for Win --- modules/shape/src/emdL1.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index 1c09ae40a8..c07e92f34f 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -393,9 +393,9 @@ bool EmdL1::greedySolution3() //- determine which direction to move, either right or upward dFlow = D[i1][i2][i3]; - f1 = i1<(binsDim1-1)?(float)fabs(float(dFlow+d1s[i1+1])):VHIGH; - f2 = i2<(binsDim2-1)?(float)fabs(float(dFlow+d2s[i2+1])):VHIGH; - f3 = i3<(binsDim3-1)?(float)fabs(float(dFlow+d3s[i3+1])):VHIGH; + f1 = i1<(binsDim1-1)?(float)fabs(double(dFlow+d1s[i1+1])):VHIGH; + f2 = i2<(binsDim2-1)?(float)fabs(double(dFlow+d2s[i2+1])):VHIGH; + f3 = i3<(binsDim3-1)?(float)fabs(double(dFlow+d3s[i3+1])):VHIGH; if(f1 Date: Wed, 25 Sep 2013 00:09:59 +0200 Subject: [PATCH 06/12] 2 Compile error fix for Win --- modules/shape/src/emdL1.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index c07e92f34f..db947b5282 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -286,7 +286,7 @@ bool EmdL1::greedySolution2() for(r=0; r fabs(dFlow+d1s[r+1])); // Move upward or right + bUpward = (r std::abs(dFlow+d1s[r+1])); // Move upward or right // modify basic variables, record BV and related values if(bUpward) @@ -308,7 +308,7 @@ bool EmdL1::greedySolution2() d2s[c+1] += dFlow; // auxilary matrix maintanence } pBV->pParent->pChild = pBV; - pBV->flow = fabs(dFlow); + pBV->flow = std::abs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward } @@ -320,7 +320,7 @@ bool EmdL1::greedySolution2() pBV = &(m_EdgesUp[r][c]); D[r+1][c] += dFlow; // auxilary matrix maintanence pBV->pParent->pChild= pBV; - pBV->flow = fabs(dFlow); + pBV->flow = std::abs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward } return true; @@ -393,9 +393,9 @@ bool EmdL1::greedySolution3() //- determine which direction to move, either right or upward dFlow = D[i1][i2][i3]; - f1 = i1<(binsDim1-1)?(float)fabs(double(dFlow+d1s[i1+1])):VHIGH; - f2 = i2<(binsDim2-1)?(float)fabs(double(dFlow+d2s[i2+1])):VHIGH; - f3 = i3<(binsDim3-1)?(float)fabs(double(dFlow+d3s[i3+1])):VHIGH; + f1 = (i1<(binsDim1-1))?std::abs(dFlow+d1s[i1+1]):VHIGH; + f2 = (i2<(binsDim2-1))?std::abs(dFlow+d2s[i2+1]):VHIGH; + f3 = (i3<(binsDim3-1))?std::abs(dFlow+d3s[i3+1]):VHIGH; if(f1flow = fabs(dFlow); + pBV->flow = std::abs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward pBV->pParent->pChild= pBV; } From 1bf4298251231a38b99e7f342b3f7a928cf46366 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Wed, 25 Sep 2013 14:13:42 +0200 Subject: [PATCH 07/12] Macro removal --- modules/shape/src/emdL1.cpp | 18 +++++++++--------- modules/shape/src/emdL1_def.hpp | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index db947b5282..b8381de5a2 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -51,7 +51,7 @@ #include "precomp.hpp" #include "emdL1_def.hpp" - +#include /****************************************************************************************\ * EMDL1 Class * @@ -286,7 +286,7 @@ bool EmdL1::greedySolution2() for(r=0; r std::abs(dFlow+d1s[r+1])); // Move upward or right + bUpward = (r fabs(dFlow+d1s[r+1])); // Move upward or right // modify basic variables, record BV and related values if(bUpward) @@ -308,7 +308,7 @@ bool EmdL1::greedySolution2() d2s[c+1] += dFlow; // auxilary matrix maintanence } pBV->pParent->pChild = pBV; - pBV->flow = std::abs(dFlow); + pBV->flow = fabs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward } @@ -320,7 +320,7 @@ bool EmdL1::greedySolution2() pBV = &(m_EdgesUp[r][c]); D[r+1][c] += dFlow; // auxilary matrix maintanence pBV->pParent->pChild= pBV; - pBV->flow = std::abs(dFlow); + pBV->flow = fabs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward } return true; @@ -393,9 +393,9 @@ bool EmdL1::greedySolution3() //- determine which direction to move, either right or upward dFlow = D[i1][i2][i3]; - f1 = (i1<(binsDim1-1))?std::abs(dFlow+d1s[i1+1]):VHIGH; - f2 = (i2<(binsDim2-1))?std::abs(dFlow+d2s[i2+1]):VHIGH; - f3 = (i3<(binsDim3-1))?std::abs(dFlow+d3s[i3+1]):VHIGH; + f1 = (i1<(binsDim1-1))?fabs(dFlow+d1s[i1+1]):std::numeric_limits::max(); + f2 = (i2<(binsDim2-1))?fabs(dFlow+d2s[i2+1]):std::numeric_limits::max(); + f3 = (i3<(binsDim3-1))?fabs(dFlow+d3s[i3+1]):std::numeric_limits::max(); if(f1flow = std::abs(dFlow); + pBV->flow = fabs(dFlow); pBV->iDir = dFlow>0; // 1:outward, 0:inward pBV->pParent->pChild= pBV; } @@ -679,7 +679,7 @@ void EmdL1::findNewSolution() void EmdL1::findLoopFromEnterBV() { // Initialize Leaving-BV edge - float minFlow = VHIGH; + float minFlow = std::numeric_limits::max(); cvPEmdEdge pE = NULL; int iLFlag = 0; // 0: in the FROM list, 1: in the TO list diff --git a/modules/shape/src/emdL1_def.hpp b/modules/shape/src/emdL1_def.hpp index 2a75ab4d48..38f78cc3d5 100644 --- a/modules/shape/src/emdL1_def.hpp +++ b/modules/shape/src/emdL1_def.hpp @@ -44,7 +44,6 @@ #include #include -#define VHIGH 1e10; /****************************************************************************************\ * For EMDL1 Framework * \****************************************************************************************/ From 4672a70c1f5c969ae48926eea1c166e32b1939a3 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Wed, 25 Sep 2013 18:30:33 +0200 Subject: [PATCH 08/12] Replaced dynamic_cas with Ptr::dynamicCast<>, and & with && --- modules/shape/src/aff_trans.cpp | 4 ++-- modules/shape/src/emdL1.cpp | 2 +- modules/shape/src/haus_dis.cpp | 6 +++--- modules/shape/src/sc_dis.cpp | 28 ++++++++++++++-------------- modules/shape/src/tps_trans.cpp | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/modules/shape/src/aff_trans.cpp b/modules/shape/src/aff_trans.cpp index 02f290fec0..c290e3fa15 100644 --- a/modules/shape/src/aff_trans.cpp +++ b/modules/shape/src/aff_trans.cpp @@ -186,7 +186,7 @@ void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray { Mat pts1 = _pts1.getMat(); Mat pts2 = _pts2.getMat(); - CV_Assert((pts1.channels()==2) & (pts1.cols>0) & (pts2.channels()==2) & (pts2.cols>0)); + CV_Assert((pts1.channels()==2) && (pts1.cols>0) && (pts2.channels()==2) && (pts2.cols>0)); CV_Assert(_matches.size()>1); if (pts1.type() != CV_32F) @@ -230,7 +230,7 @@ void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray float AffineTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts) { Mat pts1 = inPts.getMat(); - CV_Assert((pts1.channels()==2) & (pts1.cols>0)); + CV_Assert((pts1.channels()==2) && (pts1.cols>0)); //Apply transformation in the complete set of points Mat fAffine; diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp index b8381de5a2..75f1b13ad5 100644 --- a/modules/shape/src/emdL1.cpp +++ b/modules/shape/src/emdL1.cpp @@ -60,7 +60,7 @@ float EmdL1::getEMDL1(cv::Mat &sig1, cv::Mat &sig2) { // Initialization - CV_Assert((sig1.rows==sig2.rows) & (sig1.cols==sig2.cols) & (!sig1.empty()) & (!sig2.empty())); + CV_Assert((sig1.rows==sig2.rows) && (sig1.cols==sig2.cols) && (!sig1.empty()) && (!sig2.empty())); if(!initBaseTrees(sig1.rows, 1)) return -1; diff --git a/modules/shape/src/haus_dis.cpp b/modules/shape/src/haus_dis.cpp index a2c555ed7c..ff5bd8c3d1 100644 --- a/modules/shape/src/haus_dis.cpp +++ b/modules/shape/src/haus_dis.cpp @@ -71,7 +71,7 @@ public: virtual void setRankProportion(float _rankProportion) { - CV_Assert((_rankProportion>0) & (_rankProportion<=1)); + CV_Assert((_rankProportion>0) && (_rankProportion<=1)); rankProportion=_rankProportion; } virtual float getRankProportion() const {return rankProportion;} @@ -135,8 +135,8 @@ float HausdorffDistanceExtractorImpl::computeDistance(InputArray contour1, Input set1.convertTo(set1, CV_32F); if (set2.type() != CV_32F) set2.convertTo(set2, CV_32F); - CV_Assert((set1.channels()==2) & (set1.cols>0)); - CV_Assert((set2.channels()==2) & (set2.cols>0)); + CV_Assert((set1.channels()==2) && (set1.cols>0)); + CV_Assert((set2.channels()==2) && (set2.cols>0)); return std::max( _apply(set1, set2, distanceFlag, rankProportion), _apply(set2, set1, distanceFlag, rankProportion) ); } diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index e41efc2298..f19080b86c 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -45,7 +45,7 @@ * Belongie et al., 2002 by Juan Manuel Perez for GSoC 2013. */ #include "precomp.hpp" -//#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" /* * ShapeContextDescriptor class */ @@ -181,7 +181,7 @@ protected: { if (queryInliers.size()>0) { - mask.at(i,j)=char(queryInliers[j] & queryInliers[i]); + mask.at(i,j)=char(queryInliers[j] && queryInliers[i]); } else { @@ -641,14 +641,14 @@ public: virtual void setImages(InputArray _image1, InputArray _image2) { Mat image1_=_image1.getMat(), image2_=_image2.getMat(); - CV_Assert((image1_.depth()==0) & (image2_.depth()==0)); + CV_Assert((image1_.depth()==0) && (image2_.depth()==0)); image1=image1_; image2=image2_; } virtual void getImages(OutputArray _image1, OutputArray _image2) const { - CV_Assert((!image1.empty()) & (!image2.empty())); + CV_Assert((!image1.empty()) && (!image2.empty())); _image1.create(image1.size(), image1.type()); _image2.create(image2.size(), image2.type()); _image1.getMat()=image1; @@ -726,11 +726,11 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In else sset1.copyTo(set2); - CV_Assert((set1.channels()==2) & (set1.cols>0)); - CV_Assert((set2.channels()==2) & (set2.cols>0)); + CV_Assert((set1.channels()==2) && (set1.cols>0)); + CV_Assert((set2.channels()==2) && (set2.cols>0)); if (imageAppearanceWeight!=0) { - CV_Assert((!image1.empty()) & (!image2.empty())); + CV_Assert((!image1.empty()) && (!image2.empty())); } // Initializing Extractor, Descriptor structures and Matcher // @@ -747,9 +747,9 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In // Initializing some variables // std::vector inliers1, inliers2; - bool isTPS=false; - if ( dynamic_cast(&*transformer) ) - isTPS=true; + + Ptr transDown = transformer.dynamicCast(); + Mat warpedImage; for (int ii=0; ii(&*transformer)->setRegularizationParameter(beta); + if ( !transDown.empty() ) + transDown->setRegularizationParameter(beta); transformer->estimateTransformation(set1, set2, matches); bEnergy += transformer->applyTransformation(set1, set1); @@ -777,7 +777,7 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In // Have to accumulate the transformation along all the iterations if (ii==0) { - if ( isTPS ) + if ( !transDown.empty() ) { image2.copyTo(warpedImage); } @@ -794,7 +794,7 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In if (imageAppearanceWeight!=0) { // compute appearance cost - if ( isTPS ) + if ( !transDown.empty() ) { resize(warpedImage, warpedImage, image1.size()); Mat temp=(warpedImage-image1); diff --git a/modules/shape/src/tps_trans.cpp b/modules/shape/src/tps_trans.cpp index b841567dca..cbf2d1b998 100644 --- a/modules/shape/src/tps_trans.cpp +++ b/modules/shape/src/tps_trans.cpp @@ -169,7 +169,7 @@ float ThinPlateSplineShapeTransformerImpl::applyTransformation(InputArray inPts, { CV_Assert(tpsComputed); Mat pts1 = inPts.getMat(); - CV_Assert((pts1.channels()==2) & (pts1.cols>0)); + CV_Assert((pts1.channels()==2) && (pts1.cols>0)); //Apply transformation in the complete set of points // Ensambling output // @@ -192,7 +192,7 @@ void ThinPlateSplineShapeTransformerImpl::estimateTransformation(InputArray _pts { Mat pts1 = _pts1.getMat(); Mat pts2 = _pts2.getMat(); - CV_Assert((pts1.channels()==2) & (pts1.cols>0) & (pts2.channels()==2) & (pts2.cols>0)); + CV_Assert((pts1.channels()==2) && (pts1.cols>0) && (pts2.channels()==2) && (pts2.cols>0)); CV_Assert(_matches.size()>1); if (pts1.type() != CV_32F) From f6fc39ce8ff602302b6f2be1890bf1fd96ea5868 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Wed, 25 Sep 2013 23:25:10 +0200 Subject: [PATCH 09/12] Putting definitions of SCD and SCDMatcher separated from sc_dis.cpp file --- modules/shape/src/sc_dis.cpp | 989 ++++++++++++++++------------------ modules/shape/src/scd_def.hpp | 128 +++++ 2 files changed, 589 insertions(+), 528 deletions(-) create mode 100644 modules/shape/src/scd_def.hpp diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index f19080b86c..fc5ed426f0 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -46,532 +46,7 @@ */ #include "precomp.hpp" #include "opencv2/core.hpp" -/* - * ShapeContextDescriptor class - */ -class SCD -{ -public: - //! the full constructor taking all the necessary parameters - explicit SCD(int _nAngularBins=12, int _nRadialBins=5, - double _innerRadius=0.1, double _outerRadius=1, bool _rotationInvariant=false) - { - setAngularBins(_nAngularBins); - setRadialBins(_nRadialBins); - setInnerRadius(_innerRadius); - setOuterRadius(_outerRadius); - setRotationInvariant(_rotationInvariant); - } - - void extractSCD(cv::Mat& contour, cv::Mat& descriptors, - const std::vector& queryInliers=std::vector(), - const float _meanDistance=-1) - { - cv::Mat contourMat = contour; - cv::Mat disMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); - cv::Mat angleMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); - - std::vector logspaces, angspaces; - logarithmicSpaces(logspaces); - angularSpaces(angspaces); - buildNormalizedDistanceMatrix(contourMat, disMatrix, queryInliers, _meanDistance); - buildAngleMatrix(contourMat, angleMatrix); - - // Now, build the descriptor matrix (each row is a point) // - descriptors = cv::Mat::zeros(contourMat.cols, descriptorSize(), CV_32F); - - for (int ptidx=0; ptidx0) - { - if (queryInliers[ptidx]==0 || queryInliers[cmp]==0) continue; //avoid outliers - } - - int angidx=-1, radidx=-1; - for (int i=0; i(ptidx, cmp)(ptidx, cmp)(ptidx, idx)++; - } - } - } - } - - int descriptorSize() {return nAngularBins*nRadialBins;} - void setAngularBins(int angularBins) { nAngularBins=angularBins; } - void setRadialBins(int radialBins) { nRadialBins=radialBins; } - void setInnerRadius(double _innerRadius) { innerRadius=_innerRadius; } - void setOuterRadius(double _outerRadius) { outerRadius=_outerRadius; } - void setRotationInvariant(bool _rotationInvariant) { rotationInvariant=_rotationInvariant; } - int getAngularBins() const { return nAngularBins; } - int getRadialBins() const { return nRadialBins; } - double getInnerRadius() const { return innerRadius; } - double getOuterRadius() const { return outerRadius; } - bool getRotationInvariant() const { return rotationInvariant; } - float getMeanDistance() const { return meanDistance; } - -private: - int nAngularBins; - int nRadialBins; - double innerRadius; - double outerRadius; - bool rotationInvariant; - float meanDistance; - -protected: - void logarithmicSpaces(std::vector& vecSpaces) const - { - double logmin=log10(innerRadius); - double logmax=log10(outerRadius); - double delta=(logmax-logmin)/(nRadialBins-1); - double accdelta=0; - - for (int i=0; i& vecSpaces) const - { - double delta=2*CV_PI/nAngularBins; - double val=0; - - for (int i=0; i &queryInliers, - const float _meanDistance=-1) - { - cv::Mat contourMat = contour; - cv::Mat mask(disMatrix.rows, disMatrix.cols, CV_8U); - - for (int i=0; i(i,j) = (float)norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); - if (_meanDistance<0) - { - if (queryInliers.size()>0) - { - mask.at(i,j)=char(queryInliers[j] && queryInliers[i]); - } - else - { - mask.at(i,j)=1; - } - } - } - } - - if (_meanDistance<0) - { - meanDistance=(float)mean(disMatrix, mask)[0]; - } - else - { - meanDistance=_meanDistance; - } - disMatrix/=meanDistance+FLT_EPSILON; - } - - void buildAngleMatrix(cv::Mat& contour, - cv::Mat& angleMatrix) const - { - cv::Mat contourMat = contour; - - // if descriptor is rotationInvariant compute massCenter // - cv::Point2f massCenter(0,0); - if (rotationInvariant) - { - for (int i=0; i(0,i); - } - massCenter.x=massCenter.x/(float)contourMat.cols; - massCenter.y=massCenter.y/(float)contourMat.cols; - } - - - for (int i=0; i(i,j)=0.0; - } - else - { - cv::Point2f dif = contourMat.at(0,i) - contourMat.at(0,j); - angleMatrix.at(i,j) = std::atan2(dif.y, dif.x); - - if (rotationInvariant) - { - cv::Point2f refPt = contourMat.at(0,i) - massCenter; - float refAngle = atan2(refPt.y, refPt.x); - angleMatrix.at(i,j) -= refAngle; - } - angleMatrix.at(i,j) = float(fmod(double(angleMatrix.at(i,j)+(double)FLT_EPSILON),2*CV_PI)+CV_PI); - //angleMatrix.at(i,j) = 1+floor( angleMatrix.at(i,j)*nAngularBins/(2*CV_PI) ); - } - } - } - } -}; - -/* - * Matcher - */ -class SCDMatcher -{ -public: - // the full constructor - SCDMatcher() - { - } - - // the matcher function using Hungarian method - void matchDescriptors(cv::Mat& descriptors1, cv::Mat& descriptors2, std::vector& matches, cv::Ptr& comparer, - std::vector& inliers1, std::vector &inliers2) - { - matches.clear(); - - // Build the cost Matrix between descriptors // - cv::Mat costMat; - buildCostMatrix(descriptors1, descriptors2, costMat, comparer); - - // Solve the matching problem using the hungarian method // - hungarian(costMat, matches, inliers1, inliers2, descriptors1.rows, descriptors2.rows); - } - - // matching cost - float getMatchingCost() const {return minMatchCost;} - -private: - float minMatchCost; - float betaAdditional; -protected: - void buildCostMatrix(const cv::Mat& descriptors1, const cv::Mat& descriptors2, - cv::Mat& costMatrix, cv::Ptr& comparer) const - { - comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix); - } - - void hungarian(cv::Mat& costMatrix, std::vector& outMatches, std::vector &inliers1, - std::vector &inliers2, int sizeScd1=0, int sizeScd2=0) - { - std::vector free(costMatrix.rows, 0), collist(costMatrix.rows, 0); - std::vector matches(costMatrix.rows, 0), colsol(costMatrix.rows), rowsol(costMatrix.rows); - std::vector d(costMatrix.rows), pred(costMatrix.rows), v(costMatrix.rows); - - const float LOWV=1e-10; - bool unassignedfound; - int i=0, imin=0, numfree=0, prvnumfree=0, f=0, i0=0, k=0, freerow=0; - int j=0, j1=0, j2=0, endofpath=0, last=0, low=0, up=0; - float min=0, h=0, umin=0, usubmin=0, v2=0; - - // COLUMN REDUCTION // - for (j = costMatrix.rows-1; j >= 0; j--) - { - // find minimum cost over rows. - min = costMatrix.at(0,j); - imin = 0; - for (i = 1; i < costMatrix.rows; i++) - if (costMatrix.at(i,j) < min) - { - min = costMatrix.at(i,j); - imin = i; - } - v[j] = min; - - if (++matches[imin] == 1) - { - rowsol[imin] = j; - colsol[j] = imin; - } - else - { - colsol[j]=-1; - } - } - - // REDUCTION TRANSFER // - for (i=0; i::max(); - for (j=0; j(i,j)-v[j] < min) - { - min=costMatrix.at(i,j)-v[j]; - } - } - } - v[j1] = v[j1]-min; - } - } - } - // AUGMENTING ROW REDUCTION // - int loopcnt = 0; - do - { - loopcnt++; - k=0; - prvnumfree=numfree; - numfree=0; - while (k < prvnumfree) - { - i=free[k]; - k++; - umin = costMatrix.at(i,0)-v[0]; - j1=0; - usubmin = std::numeric_limits::max(); - for (j=1; j(i,j)-v[j]; - if (h < usubmin) - { - if (h >= umin) - { - usubmin = h; - j2 = j; - } - else - { - usubmin = umin; - umin = h; - j2 = j1; - j1 = j; - } - } - } - i0 = colsol[j1]; - - if (fabs(umin-usubmin) > LOWV) //if( umin < usubmin ) - { - v[j1] = v[j1] - (usubmin - umin); - } - else // minimum and subminimum equal. - { - if (i0 >= 0) // minimum column j1 is assigned. - { - j1 = j2; - i0 = colsol[j2]; - } - } - // (re-)assign i to j1, possibly de-assigning an i0. - rowsol[i]=j1; - colsol[j1]=i; - - if (i0 >= 0) - { - //if( umin < usubmin ) - if (fabs(umin-usubmin) > LOWV) - { - free[--k] = i0; - } - else - { - free[numfree++] = i0; - } - } - } - }while (loopcnt<2); // repeat once. - - // AUGMENT SOLUTION for each free row // - for (f = 0; f(freerow,j) - v[j]; - pred[j] = float(freerow); - collist[j] = j; // init column list. - } - - low=0; // columns in 0..low-1 are ready, now none. - up=0; // columns in low..up-1 are to be scanned for current minimum, now none. - unassignedfound = false; - do - { - if (up == low) - { - last=low-1; - min = d[collist[up++]]; - for (k = up; k < costMatrix.rows; k++) - { - j = collist[k]; - h = d[j]; - if (h <= min) - { - if (h < min) // new minimum. - { - up = low; // restart list at index low. - min = h; - } - collist[k] = collist[up]; - collist[up++] = j; - } - } - for (k=low; k(i,j1)-v[j1]-min; - - for (k = up; k < costMatrix.rows; k++) - { - j = collist[k]; - v2 = costMatrix.at(i,j) - v[j] - h; - if (v2 < d[j]) - { - pred[j] = float(i); - if (v2 == min) - { - if (colsol[j] < 0) - { - // if unassigned, shortest augmenting path is complete. - endofpath = j; - unassignedfound = true; - break; - } - else - { - collist[k] = collist[up]; - collist[up++] = j; - } - } - d[j] = v2; - } - } - } - }while (!unassignedfound); - - // update column prices. - for (k = 0; k <= last; k++) - { - j1 = collist[k]; - v[j1] = v[j1] + d[j1] - min; - } - - // reset row and column assignments along the alternating path. - do - { - i = int(pred[endofpath]); - colsol[endofpath] = i; - j1 = endofpath; - endofpath = rowsol[i]; - rowsol[i] = j1; - }while (i != freerow); - } - - // calculate symmetric shape context cost - cv::Mat trueCostMatrix(costMatrix, cv::Rect(0,0,sizeScd1, sizeScd2)); - float leftcost = 0; - for (int nrow=0; nrow(colsol[i],i));//queryIdx,trainIdx,distance - outMatches.push_back(singleMatch); - } - - // Update inliers - inliers1.reserve(sizeScd1); - for (size_t kc = 0; kc matches; @@ -846,3 +321,461 @@ Ptr createShapeContextDistanceExtractor(int nAng } } // cv + +//! SCD +void SCD::extractSCD(cv::Mat &contour, cv::Mat &descriptors, const std::vector &queryInliers, const float _meanDistance) +{ + cv::Mat contourMat = contour; + cv::Mat disMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + cv::Mat angleMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + + std::vector logspaces, angspaces; + logarithmicSpaces(logspaces); + angularSpaces(angspaces); + buildNormalizedDistanceMatrix(contourMat, disMatrix, queryInliers, _meanDistance); + buildAngleMatrix(contourMat, angleMatrix); + + // Now, build the descriptor matrix (each row is a point) // + descriptors = cv::Mat::zeros(contourMat.cols, descriptorSize(), CV_32F); + + for (int ptidx=0; ptidx0) + { + if (queryInliers[ptidx]==0 || queryInliers[cmp]==0) continue; //avoid outliers + } + + int angidx=-1, radidx=-1; + for (int i=0; i(ptidx, cmp)(ptidx, cmp)(ptidx, idx)++; + } + } + } +} + +void SCD::logarithmicSpaces(std::vector &vecSpaces) const +{ + double logmin=log10(innerRadius); + double logmax=log10(outerRadius); + double delta=(logmax-logmin)/(nRadialBins-1); + double accdelta=0; + + for (int i=0; i &vecSpaces) const +{ + double delta=2*CV_PI/nAngularBins; + double val=0; + + for (int i=0; i &queryInliers, const float _meanDistance) +{ + cv::Mat contourMat = contour; + cv::Mat mask(disMatrix.rows, disMatrix.cols, CV_8U); + + for (int i=0; i(i,j) = (float)norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); + if (_meanDistance<0) + { + if (queryInliers.size()>0) + { + mask.at(i,j)=char(queryInliers[j] && queryInliers[i]); + } + else + { + mask.at(i,j)=1; + } + } + } + } + + if (_meanDistance<0) + { + meanDistance=(float)mean(disMatrix, mask)[0]; + } + else + { + meanDistance=_meanDistance; + } + disMatrix/=meanDistance+FLT_EPSILON; +} + +void SCD::buildAngleMatrix(cv::Mat &contour, cv::Mat &angleMatrix) const +{ + cv::Mat contourMat = contour; + + // if descriptor is rotationInvariant compute massCenter // + cv::Point2f massCenter(0,0); + if (rotationInvariant) + { + for (int i=0; i(0,i); + } + massCenter.x=massCenter.x/(float)contourMat.cols; + massCenter.y=massCenter.y/(float)contourMat.cols; + } + + + for (int i=0; i(i,j)=0.0; + } + else + { + cv::Point2f dif = contourMat.at(0,i) - contourMat.at(0,j); + angleMatrix.at(i,j) = std::atan2(dif.y, dif.x); + + if (rotationInvariant) + { + cv::Point2f refPt = contourMat.at(0,i) - massCenter; + float refAngle = atan2(refPt.y, refPt.x); + angleMatrix.at(i,j) -= refAngle; + } + angleMatrix.at(i,j) = float(fmod(double(angleMatrix.at(i,j)+(double)FLT_EPSILON),2*CV_PI)+CV_PI); + } + } + } +} + +//! SCDMatcher +void SCDMatcher::matchDescriptors(cv::Mat &descriptors1, cv::Mat &descriptors2, std::vector &matches, + cv::Ptr &comparer, std::vector &inliers1, std::vector &inliers2) +{ + matches.clear(); + + // Build the cost Matrix between descriptors // + cv::Mat costMat; + buildCostMatrix(descriptors1, descriptors2, costMat, comparer); + + // Solve the matching problem using the hungarian method // + hungarian(costMat, matches, inliers1, inliers2, descriptors1.rows, descriptors2.rows); +} + +void SCDMatcher::buildCostMatrix(const cv::Mat &descriptors1, const cv::Mat &descriptors2, + cv::Mat &costMatrix, cv::Ptr &comparer) const +{ + comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix); +} + +void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector &outMatches, std::vector &inliers1, + std::vector &inliers2, int sizeScd1, int sizeScd2) +{ + std::vector free(costMatrix.rows, 0), collist(costMatrix.rows, 0); + std::vector matches(costMatrix.rows, 0), colsol(costMatrix.rows), rowsol(costMatrix.rows); + std::vector d(costMatrix.rows), pred(costMatrix.rows), v(costMatrix.rows); + + const float LOWV=1e-10; + bool unassignedfound; + int i=0, imin=0, numfree=0, prvnumfree=0, f=0, i0=0, k=0, freerow=0; + int j=0, j1=0, j2=0, endofpath=0, last=0, low=0, up=0; + float min=0, h=0, umin=0, usubmin=0, v2=0; + + // COLUMN REDUCTION // + for (j = costMatrix.rows-1; j >= 0; j--) + { + // find minimum cost over rows. + min = costMatrix.at(0,j); + imin = 0; + for (i = 1; i < costMatrix.rows; i++) + if (costMatrix.at(i,j) < min) + { + min = costMatrix.at(i,j); + imin = i; + } + v[j] = min; + + if (++matches[imin] == 1) + { + rowsol[imin] = j; + colsol[j] = imin; + } + else + { + colsol[j]=-1; + } + } + + // REDUCTION TRANSFER // + for (i=0; i::max(); + for (j=0; j(i,j)-v[j] < min) + { + min=costMatrix.at(i,j)-v[j]; + } + } + } + v[j1] = v[j1]-min; + } + } + } + // AUGMENTING ROW REDUCTION // + int loopcnt = 0; + do + { + loopcnt++; + k=0; + prvnumfree=numfree; + numfree=0; + while (k < prvnumfree) + { + i=free[k]; + k++; + umin = costMatrix.at(i,0)-v[0]; + j1=0; + usubmin = std::numeric_limits::max(); + for (j=1; j(i,j)-v[j]; + if (h < usubmin) + { + if (h >= umin) + { + usubmin = h; + j2 = j; + } + else + { + usubmin = umin; + umin = h; + j2 = j1; + j1 = j; + } + } + } + i0 = colsol[j1]; + + if (fabs(umin-usubmin) > LOWV) //if( umin < usubmin ) + { + v[j1] = v[j1] - (usubmin - umin); + } + else // minimum and subminimum equal. + { + if (i0 >= 0) // minimum column j1 is assigned. + { + j1 = j2; + i0 = colsol[j2]; + } + } + // (re-)assign i to j1, possibly de-assigning an i0. + rowsol[i]=j1; + colsol[j1]=i; + + if (i0 >= 0) + { + //if( umin < usubmin ) + if (fabs(umin-usubmin) > LOWV) + { + free[--k] = i0; + } + else + { + free[numfree++] = i0; + } + } + } + }while (loopcnt<2); // repeat once. + + // AUGMENT SOLUTION for each free row // + for (f = 0; f(freerow,j) - v[j]; + pred[j] = float(freerow); + collist[j] = j; // init column list. + } + + low=0; // columns in 0..low-1 are ready, now none. + up=0; // columns in low..up-1 are to be scanned for current minimum, now none. + unassignedfound = false; + do + { + if (up == low) + { + last=low-1; + min = d[collist[up++]]; + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + h = d[j]; + if (h <= min) + { + if (h < min) // new minimum. + { + up = low; // restart list at index low. + min = h; + } + collist[k] = collist[up]; + collist[up++] = j; + } + } + for (k=low; k(i,j1)-v[j1]-min; + + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + v2 = costMatrix.at(i,j) - v[j] - h; + if (v2 < d[j]) + { + pred[j] = float(i); + if (v2 == min) + { + if (colsol[j] < 0) + { + // if unassigned, shortest augmenting path is complete. + endofpath = j; + unassignedfound = true; + break; + } + else + { + collist[k] = collist[up]; + collist[up++] = j; + } + } + d[j] = v2; + } + } + } + }while (!unassignedfound); + + // update column prices. + for (k = 0; k <= last; k++) + { + j1 = collist[k]; + v[j1] = v[j1] + d[j1] - min; + } + + // reset row and column assignments along the alternating path. + do + { + i = int(pred[endofpath]); + colsol[endofpath] = i; + j1 = endofpath; + endofpath = rowsol[i]; + rowsol[i] = j1; + }while (i != freerow); + } + + // calculate symmetric shape context cost + cv::Mat trueCostMatrix(costMatrix, cv::Rect(0,0,sizeScd1, sizeScd2)); + float leftcost = 0; + for (int nrow=0; nrow(colsol[i],i));//queryIdx,trainIdx,distance + outMatches.push_back(singleMatch); + } + + // Update inliers + inliers1.reserve(sizeScd1); + for (size_t kc = 0; kc +#include +#include + +/* + * ShapeContextDescriptor class + */ +class SCD +{ +public: + //! the full constructor taking all the necessary parameters + explicit SCD(int _nAngularBins=12, int _nRadialBins=5, + double _innerRadius=0.1, double _outerRadius=1, bool _rotationInvariant=false) + { + setAngularBins(_nAngularBins); + setRadialBins(_nRadialBins); + setInnerRadius(_innerRadius); + setOuterRadius(_outerRadius); + setRotationInvariant(_rotationInvariant); + } + + void extractSCD(cv::Mat& contour, cv::Mat& descriptors, + const std::vector& queryInliers=std::vector(), + const float _meanDistance=-1); + + int descriptorSize() {return nAngularBins*nRadialBins;} + void setAngularBins(int angularBins) { nAngularBins=angularBins; } + void setRadialBins(int radialBins) { nRadialBins=radialBins; } + void setInnerRadius(double _innerRadius) { innerRadius=_innerRadius; } + void setOuterRadius(double _outerRadius) { outerRadius=_outerRadius; } + void setRotationInvariant(bool _rotationInvariant) { rotationInvariant=_rotationInvariant; } + int getAngularBins() const { return nAngularBins; } + int getRadialBins() const { return nRadialBins; } + double getInnerRadius() const { return innerRadius; } + double getOuterRadius() const { return outerRadius; } + bool getRotationInvariant() const { return rotationInvariant; } + float getMeanDistance() const { return meanDistance; } + +private: + int nAngularBins; + int nRadialBins; + double innerRadius; + double outerRadius; + bool rotationInvariant; + float meanDistance; + +protected: + void logarithmicSpaces(std::vector& vecSpaces) const; + void angularSpaces(std::vector& vecSpaces) const; + + void buildNormalizedDistanceMatrix(cv::Mat& contour, + cv::Mat& disMatrix, const std::vector &queryInliers, + const float _meanDistance=-1); + + void buildAngleMatrix(cv::Mat& contour, + cv::Mat& angleMatrix) const; +}; + +/* + * Matcher + */ +class SCDMatcher +{ +public: + // the full constructor + SCDMatcher() + { + } + + // the matcher function using Hungarian method + void matchDescriptors(cv::Mat& descriptors1, cv::Mat& descriptors2, std::vector& matches, cv::Ptr& comparer, + std::vector& inliers1, std::vector &inliers2); + + // matching cost + float getMatchingCost() const {return minMatchCost;} + +private: + float minMatchCost; + float betaAdditional; +protected: + void buildCostMatrix(const cv::Mat& descriptors1, const cv::Mat& descriptors2, + cv::Mat& costMatrix, cv::Ptr& comparer) const; + void hungarian(cv::Mat& costMatrix, std::vector& outMatches, std::vector &inliers1, + std::vector &inliers2, int sizeScd1=0, int sizeScd2=0); + +}; From cd847425562caa2cc309b41c18eef7cb47485818 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 30 Sep 2013 14:53:48 +0400 Subject: [PATCH 10/12] attempts to fix build errors on Android --- modules/shape/src/sc_dis.cpp | 23 ++++++++++++----------- modules/shape/src/scd_def.hpp | 5 +++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index fc5ed426f0..e09f7738e3 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -166,7 +166,7 @@ public: sigma = (float)fn["sigma"]; } -private: +protected: int nAngularBins; int nRadialBins; float innerRadius; @@ -182,8 +182,6 @@ private: float imageAppearanceWeight; float shapeContextWeight; float sigma; - -protected: String name_; }; @@ -226,7 +224,9 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In Ptr transDown = transformer.dynamicCast(); Mat warpedImage; - for (int ii=0; ii(0,pt).x; float yy = sset1.at(0,pt).y; @@ -297,9 +297,9 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In } Mat appIm(diffIm.rows, diffIm.cols, CV_32F); - for (int ii=0; ii(ii,jj) )/255; float elemb=gaussWindow.at(ii,jj); @@ -320,8 +320,6 @@ Ptr createShapeContextDistanceExtractor(int nAng outerRadius, iterations, comparer, transformer) ); } -} // cv - //! SCD void SCD::extractSCD(cv::Mat &contour, cv::Mat &descriptors, const std::vector &queryInliers, const float _meanDistance) { @@ -779,3 +777,6 @@ void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector &outMatc inliers2[kc]=0; } } + +} + diff --git a/modules/shape/src/scd_def.hpp b/modules/shape/src/scd_def.hpp index c7476ea5a4..18b3e9a78e 100644 --- a/modules/shape/src/scd_def.hpp +++ b/modules/shape/src/scd_def.hpp @@ -44,6 +44,8 @@ #include #include +namespace cv +{ /* * ShapeContextDescriptor class */ @@ -126,3 +128,6 @@ protected: std::vector &inliers2, int sizeScd1=0, int sizeScd2=0); }; + +} + From c3748a5f95f6c6e1a6c8024ebb30cd4c58e1f45d Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 30 Sep 2013 16:06:48 +0400 Subject: [PATCH 11/12] fixed the trailing whitespaces --- modules/shape/src/sc_dis.cpp | 1 - modules/shape/src/scd_def.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index e09f7738e3..7a0893d5a9 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -779,4 +779,3 @@ void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector &outMatc } } - diff --git a/modules/shape/src/scd_def.hpp b/modules/shape/src/scd_def.hpp index 18b3e9a78e..1a180fd847 100644 --- a/modules/shape/src/scd_def.hpp +++ b/modules/shape/src/scd_def.hpp @@ -130,4 +130,3 @@ protected: }; } - From c810d03d5c1e2d4a28987919f9c3dcbfecdc676c Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 30 Sep 2013 19:28:11 +0400 Subject: [PATCH 12/12] some more attempts to fix compile bug on Android --- modules/shape/src/sc_dis.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index 7a0893d5a9..24e86af491 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -235,7 +235,8 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In set2SCE.extractSCD(set2, set2SCD, inliers2, set1SCE.getMeanDistance()); // regularization parameter with annealing rate annRate // - beta=std::pow(set1SCE.getMeanDistance(),2); + beta=set1SCE.getMeanDistance(); + beta *= beta; // match // matcher.matchDescriptors(set1SCD, set2SCD, matches, comparer, inliers1, inliers2); @@ -284,13 +285,12 @@ float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, In gaussWindow = Mat::zeros(warpedImage.rows, warpedImage.cols, CV_32F); for (pt=0; pt(0,pt); for (ii=0; ii(0,pt).x; - float yy = sset1.at(0,pt).y; - float val = float(std::exp( -float( (xx-jj)*(xx-jj) + (yy-ii)*(yy-ii) )/(2*sigma*sigma) ) / (sigma*sigma*2*CV_PI)); + float val = float(std::exp( -float( (p.x-jj)*(p.x-jj) + (p.y-ii)*(p.y-ii) )/(2*sigma*sigma) ) / (sigma*sigma*2*CV_PI)); gaussWindow.at(ii,jj) += val; } }