From 47ce461d97640c553cc752b527c146691ecb6054 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Fri, 31 May 2013 07:39:15 +0300 Subject: [PATCH 01/22] The initial commit for generic optimization Generic optimization package for openCV project, will be developed between the June and September of 2013. This work is funded by Google Summer of Code 2013 project. This project is about implementing several algorithms, that will find global maxima/minima of a given function on a given domain subject to a given constraints. All comments/suggestions are warmly appreciated and to be sent to alozz1991@gmail.com (please, mention the word "openCV" in topic of message, for I'm using the spam-filters) --- modules/optim/CMakeLists.txt | 2 + modules/optim/doc/denoising.rst | 91 ++ modules/optim/doc/inpainting.rst | 32 + modules/optim/doc/photo.rst | 11 + modules/optim/include/opencv2/photo.hpp | 85 ++ modules/optim/include/opencv2/photo/photo.hpp | 48 + modules/optim/include/opencv2/photo/photo_c.h | 69 ++ modules/optim/perf/perf_inpaint.cpp | 38 + modules/optim/perf/perf_main.cpp | 3 + modules/optim/perf/perf_precomp.cpp | 1 + modules/optim/perf/perf_precomp.hpp | 20 + modules/optim/src/arrays.hpp | 161 ++++ modules/optim/src/denoising.cpp | 242 ++++++ .../src/fast_nlmeans_denoising_invoker.hpp | 334 +++++++ ...fast_nlmeans_denoising_invoker_commons.hpp | 115 +++ .../fast_nlmeans_multi_denoising_invoker.hpp | 383 ++++++++ modules/optim/src/inpaint.cpp | 817 ++++++++++++++++++ modules/optim/src/precomp.cpp | 44 + modules/optim/src/precomp.hpp | 53 ++ modules/optim/test/test_denoising.cpp | 158 ++++ modules/optim/test/test_inpaint.cpp | 119 +++ modules/optim/test/test_main.cpp | 3 + modules/optim/test/test_precomp.cpp | 1 + modules/optim/test/test_precomp.hpp | 17 + 24 files changed, 2847 insertions(+) create mode 100644 modules/optim/CMakeLists.txt create mode 100644 modules/optim/doc/denoising.rst create mode 100644 modules/optim/doc/inpainting.rst create mode 100644 modules/optim/doc/photo.rst create mode 100644 modules/optim/include/opencv2/photo.hpp create mode 100644 modules/optim/include/opencv2/photo/photo.hpp create mode 100644 modules/optim/include/opencv2/photo/photo_c.h create mode 100644 modules/optim/perf/perf_inpaint.cpp create mode 100644 modules/optim/perf/perf_main.cpp create mode 100644 modules/optim/perf/perf_precomp.cpp create mode 100644 modules/optim/perf/perf_precomp.hpp create mode 100644 modules/optim/src/arrays.hpp create mode 100644 modules/optim/src/denoising.cpp create mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker.hpp create mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp create mode 100644 modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp create mode 100644 modules/optim/src/inpaint.cpp create mode 100644 modules/optim/src/precomp.cpp create mode 100644 modules/optim/src/precomp.hpp create mode 100644 modules/optim/test/test_denoising.cpp create mode 100644 modules/optim/test/test_inpaint.cpp create mode 100644 modules/optim/test/test_main.cpp create mode 100644 modules/optim/test/test_precomp.cpp create mode 100644 modules/optim/test/test_precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt new file mode 100644 index 0000000000..08a72ea928 --- /dev/null +++ b/modules/optim/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Computational Photography") +ocv_define_module(photo opencv_imgproc) diff --git a/modules/optim/doc/denoising.rst b/modules/optim/doc/denoising.rst new file mode 100644 index 0000000000..97625d3b31 --- /dev/null +++ b/modules/optim/doc/denoising.rst @@ -0,0 +1,91 @@ +Denoising +========== + +.. highlight:: cpp + +fastNlMeansDenoising +-------------------- +Perform image denoising using Non-local Means Denoising algorithm http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ +with several computational optimizations. Noise expected to be a gaussian white noise + +.. ocv:function:: void fastNlMeansDenoising( InputArray src, OutputArray dst, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param src: Input 8-bit 1-channel, 2-channel or 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength. Big h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +This function expected to be applied to grayscale images. For colored images look at ``fastNlMeansDenoisingColored``. +Advanced usage of this functions can be manual denoising of colored image in different colorspaces. +Such approach is used in ``fastNlMeansDenoisingColored`` by converting image to CIELAB colorspace and then separately denoise L and AB components with different h parameter. + +fastNlMeansDenoisingColored +--------------------------- +Modification of ``fastNlMeansDenoising`` function for colored images + +.. ocv:function:: void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + + :param hForColorComponents: The same as h but for color components. For most images value equals 10 will be enought to remove colored noise and do not distort colors + +The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoising`` function. + +fastNlMeansDenoisingMulti +------------------------- +Modification of ``fastNlMeansDenoising`` function for images sequence where consequtive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. +For more details see http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.6394 + +.. ocv:function:: void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param srcImgs: Input 8-bit 1-channel, 2-channel or 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +fastNlMeansDenoisingColoredMulti +-------------------------------- +Modification of ``fastNlMeansDenoisingMulti`` function for colored images sequences + +.. ocv:function:: void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) + + :param srcImgs: Input 8-bit 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise. + + :param hForColorComponents: The same as h but for color components. + +The function converts images to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoisingMulti`` function. + diff --git a/modules/optim/doc/inpainting.rst b/modules/optim/doc/inpainting.rst new file mode 100644 index 0000000000..9b66266136 --- /dev/null +++ b/modules/optim/doc/inpainting.rst @@ -0,0 +1,32 @@ +Inpainting +========== + +.. highlight:: cpp + +inpaint +----------- +Restores the selected region in an image using the region neighborhood. + +.. ocv:function:: void inpaint( InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags ) + +.. ocv:pyfunction:: cv2.inpaint(src, inpaintMask, inpaintRadius, flags[, dst]) -> dst + +.. ocv:cfunction:: void cvInpaint( const CvArr* src, const CvArr* inpaint_mask, CvArr* dst, double inpaintRange, int flags ) + + :param src: Input 8-bit 1-channel or 3-channel image. + + :param inpaintMask: Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted. + + :param dst: Output image with the same size and type as ``src`` . + + :param inpaintRadius: Radius of a circular neighborhood of each point inpainted that is considered by the algorithm. + + :param flags: Inpainting method that could be one of the following: + + * **INPAINT_NS** Navier-Stokes based method. + + * **INPAINT_TELEA** Method by Alexandru Telea [Telea04]_. + +The function reconstructs the selected image area from the pixel near the area boundary. The function may be used to remove dust and scratches from a scanned photo, or to remove undesirable objects from still images or video. See +http://en.wikipedia.org/wiki/Inpainting +for more details. diff --git a/modules/optim/doc/photo.rst b/modules/optim/doc/photo.rst new file mode 100644 index 0000000000..fa2aa1ecb8 --- /dev/null +++ b/modules/optim/doc/photo.rst @@ -0,0 +1,11 @@ +******************************** +photo. Computational Photography +******************************** + +.. highlight:: cpp + +.. toctree:: + :maxdepth: 2 + + inpainting + denoising diff --git a/modules/optim/include/opencv2/photo.hpp b/modules/optim/include/opencv2/photo.hpp new file mode 100644 index 0000000000..185b8dcc90 --- /dev/null +++ b/modules/optim/include/opencv2/photo.hpp @@ -0,0 +1,85 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-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_PHOTO_HPP__ +#define __OPENCV_PHOTO_HPP__ + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" + +/*! \namespace cv + Namespace where all the C++ OpenCV functionality resides + */ +namespace cv +{ + +//! the inpainting algorithm +enum +{ + INPAINT_NS = 0, // Navier-Stokes algorithm + INPAINT_TELEA = 1 // A. Telea algorithm +}; + +//! restores the damaged image areas using one of the available intpainting algorithms +CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, + OutputArray dst, double inpaintRadius, int flags ); + + +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); + +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); + +} // cv + +#endif diff --git a/modules/optim/include/opencv2/photo/photo.hpp b/modules/optim/include/opencv2/photo/photo.hpp new file mode 100644 index 0000000000..41aa7ae405 --- /dev/null +++ b/modules/optim/include/opencv2/photo/photo.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/photo.hpp" \ No newline at end of file diff --git a/modules/optim/include/opencv2/photo/photo_c.h b/modules/optim/include/opencv2/photo/photo_c.h new file mode 100644 index 0000000000..4ca05f2538 --- /dev/null +++ b/modules/optim/include/opencv2/photo/photo_c.h @@ -0,0 +1,69 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using 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) 2008-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_PHOTO_C_H__ +#define __OPENCV_PHOTO_C_H__ + +#include "opencv2/core/core_c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Inpainting algorithms */ +enum +{ + CV_INPAINT_NS =0, + CV_INPAINT_TELEA =1 +}; + + +/* Inpaints the selected region in the image */ +CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask, + CvArr* dst, double inpaintRange, int flags ); + + +#ifdef __cplusplus +} //extern "C" +#endif + +#endif //__OPENCV_PHOTO_C_H__ diff --git a/modules/optim/perf/perf_inpaint.cpp b/modules/optim/perf/perf_inpaint.cpp new file mode 100644 index 0000000000..2debcf5c5e --- /dev/null +++ b/modules/optim/perf/perf_inpaint.cpp @@ -0,0 +1,38 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(InpaintingMethod, INPAINT_NS, INPAINT_TELEA) +typedef std::tr1::tuple InpaintArea_InpaintingMethod_t; +typedef perf::TestBaseWithParam InpaintArea_InpaintingMethod; + + +PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint, + testing::Combine( + testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64), + InpaintingMethod::all() + ) + ) +{ + Mat src = imread(getDataPath("gpu/hog/road.png")); + + Size sz = get<0>(GetParam()); + int inpaintingMethod = get<1>(GetParam()); + + Mat mask(src.size(), CV_8UC1, Scalar(0)); + Mat result(src.size(), src.type()); + + Rect inpaintArea(src.cols/3, src.rows/3, sz.width, sz.height); + mask(inpaintArea).setTo(255); + + declare.in(src, mask).out(result).time(120); + + TEST_CYCLE() inpaint(src, mask, result, 10.0, inpaintingMethod); + + Mat inpaintedArea = result(inpaintArea); + SANITY_CHECK(inpaintedArea); +} diff --git a/modules/optim/perf/perf_main.cpp b/modules/optim/perf/perf_main.cpp new file mode 100644 index 0000000000..f5863c1974 --- /dev/null +++ b/modules/optim/perf/perf_main.cpp @@ -0,0 +1,3 @@ +#include "perf_precomp.hpp" + +CV_PERF_TEST_MAIN(photo) diff --git a/modules/optim/perf/perf_precomp.cpp b/modules/optim/perf/perf_precomp.cpp new file mode 100644 index 0000000000..8552ac3d42 --- /dev/null +++ b/modules/optim/perf/perf_precomp.cpp @@ -0,0 +1 @@ +#include "perf_precomp.hpp" diff --git a/modules/optim/perf/perf_precomp.hpp b/modules/optim/perf/perf_precomp.hpp new file mode 100644 index 0000000000..1fd0c81093 --- /dev/null +++ b/modules/optim/perf/perf_precomp.hpp @@ -0,0 +1,20 @@ +#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_PERF_PRECOMP_HPP__ +#define __OPENCV_PERF_PRECOMP_HPP__ + +#include "opencv2/ts.hpp" +#include "opencv2/photo.hpp" +#include "opencv2/highgui.hpp" + +#ifdef GTEST_CREATE_SHARED_LIBRARY +#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined +#endif + +#endif diff --git a/modules/optim/src/arrays.hpp b/modules/optim/src/arrays.hpp new file mode 100644 index 0000000000..ae01e9af82 --- /dev/null +++ b/modules/optim/src/arrays.hpp @@ -0,0 +1,161 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_DENOISING_ARRAYS_HPP__ +#define __OPENCV_DENOISING_ARRAYS_HPP__ + +template struct Array2d { + T* a; + int n1,n2; + bool needToDeallocArray; + + Array2d(const Array2d& array2d): + a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false) + { + if (array2d.needToDeallocArray) { + // copy constructor for self allocating arrays not supported + throw new std::exception(); + } + } + + Array2d(T* _a, int _n1, int _n2): + a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {} + + Array2d(int _n1, int _n2): + n1(_n1), n2(_n2), needToDeallocArray(true) + { + a = new T[n1*n2]; + } + + ~Array2d() { + if (needToDeallocArray) { + delete[] a; + } + } + + T* operator [] (int i) { + return a + i*n2; + } + + inline T* row_ptr(int i) { + return (*this)[i]; + } +}; + +template struct Array3d { + T* a; + int n1,n2,n3; + bool needToDeallocArray; + + Array3d(T* _a, int _n1, int _n2, int _n3): + a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {} + + Array3d(int _n1, int _n2, int _n3): + n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true) + { + a = new T[n1*n2*n3]; + } + + ~Array3d() { + if (needToDeallocArray) { + delete[] a; + } + } + + Array2d operator [] (int i) { + Array2d array2d(a + i*n2*n3, n2, n3); + return array2d; + } + + inline T* row_ptr(int i1, int i2) { + return a + i1*n2*n3 + i2*n3; + } +}; + +template struct Array4d { + T* a; + int n1,n2,n3,n4; + bool needToDeallocArray; + int steps[4]; + + void init_steps() { + steps[0] = n2*n3*n4; + steps[1] = n3*n4; + steps[2] = n4; + steps[3] = 1; + } + + Array4d(T* _a, int _n1, int _n2, int _n3, int _n4): + a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false) + { + init_steps(); + } + + Array4d(int _n1, int _n2, int _n3, int _n4): + n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true) + { + a = new T[n1*n2*n3*n4]; + init_steps(); + } + + ~Array4d() { + if (needToDeallocArray) { + delete[] a; + } + } + + Array3d operator [] (int i) { + Array3d array3d(a + i*n2*n3*n4, n2, n3, n4); + return array3d; + } + + inline T* row_ptr(int i1, int i2, int i3) { + return a + i1*n2*n3*n4 + i2*n3*n4 + i3*n4; + } + + inline int step_size(int dimension) { + return steps[dimension]; + } +}; + +#endif + + diff --git a/modules/optim/src/denoising.cpp b/modules/optim/src/denoising.cpp new file mode 100644 index 0000000000..4d3e6c8f94 --- /dev/null +++ b/modules/optim/src/denoising.cpp @@ -0,0 +1,242 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "fast_nlmeans_denoising_invoker.hpp" +#include "fast_nlmeans_multi_denoising_invoker.hpp" + +void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h, + int templateWindowSize, int searchWindowSize) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + +#ifdef HAVE_TEGRA_OPTIMIZATION + if(tegra::fastNlMeansDenoising(src, dst, h, templateWindowSize, searchWindowSize)) + return; +#endif + + switch (src.type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(Error::StsBadArg, + "Unsupported image format! Only CV_8UC1, CV_8UC2 and CV_8UC3 are supported"); + } +} + +void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst, + float h, float hForColorComponents, + int templateWindowSize, int searchWindowSize) +{ + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + if (src.type() != CV_8UC3) { + CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3!"); + return; + } + + Mat src_lab; + cvtColor(src, src_lab, COLOR_LBGR2Lab); + + Mat l(src.size(), CV_8U); + Mat ab(src.size(), CV_8UC2); + Mat l_ab[] = { l, ab }; + int from_to[] = { 0,0, 1,1, 2,2 }; + mixChannels(&src_lab, 1, l_ab, 2, from_to, 3); + + fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize); + fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize); + + Mat l_ab_denoised[] = { l, ab }; + Mat dst_lab(src.size(), src.type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, COLOR_Lab2LBGR); +} + +static void fastNlMeansDenoisingMultiCheckPreconditions( + const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + int templateWindowSize, int searchWindowSize) +{ + int src_imgs_size = (int)srcImgs.size(); + if (src_imgs_size == 0) { + CV_Error(Error::StsBadArg, "Input images vector should not be empty!"); + } + + if (temporalWindowSize % 2 == 0 || + searchWindowSize % 2 == 0 || + templateWindowSize % 2 == 0) { + CV_Error(Error::StsBadArg, "All windows sizes should be odd!"); + } + + int temporalWindowHalfSize = temporalWindowSize / 2; + if (imgToDenoiseIndex - temporalWindowHalfSize < 0 || + imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size) + { + CV_Error(Error::StsBadArg, + "imgToDenoiseIndex and temporalWindowSize " + "should be choosen corresponding srcImgs size!"); + } + + for (int i = 1; i < src_imgs_size; i++) { + if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type()) { + CV_Error(Error::StsBadArg, "Input images should have the same size and type!"); + } + } +} + +void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h, int templateWindowSize, int searchWindowSize) +{ + std::vector srcImgs; + _srcImgs.getMatVector(srcImgs); + + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); + + switch (srcImgs[0].type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(Error::StsBadArg, + "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); + } +} + +void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, + int imgToDenoiseIndex, int temporalWindowSize, + float h, float hForColorComponents, + int templateWindowSize, int searchWindowSize) +{ + std::vector srcImgs; + _srcImgs.getMatVector(srcImgs); + + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); + + int src_imgs_size = (int)srcImgs.size(); + + if (srcImgs[0].type() != CV_8UC3) { + CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!"); + return; + } + + int from_to[] = { 0,0, 1,1, 2,2 }; + + // TODO convert only required images + std::vector src_lab(src_imgs_size); + std::vector l(src_imgs_size); + std::vector ab(src_imgs_size); + for (int i = 0; i < src_imgs_size; i++) { + src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3); + l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1); + ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2); + cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab); + + Mat l_ab[] = { l[i], ab[i] }; + mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3); + } + + Mat dst_l; + Mat dst_ab; + + fastNlMeansDenoisingMulti( + l, dst_l, imgToDenoiseIndex, temporalWindowSize, + h, templateWindowSize, searchWindowSize); + + fastNlMeansDenoisingMulti( + ab, dst_ab, imgToDenoiseIndex, temporalWindowSize, + hForColorComponents, templateWindowSize, searchWindowSize); + + Mat l_ab_denoised[] = { dst_l, dst_ab }; + Mat dst_lab(srcImgs[0].size(), srcImgs[0].type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, COLOR_Lab2LBGR); +} + + diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp new file mode 100644 index 0000000000..232dba88da --- /dev/null +++ b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp @@ -0,0 +1,334 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace cv; + +template +struct FastNlMeansDenoisingInvoker { + public: + FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, + int template_window_size, int search_window_size, const float h); + + void operator() (const BlockedRange& range) const; + + private: + void operator= (const FastNlMeansDenoisingInvoker&); + + const Mat& src_; + Mat& dst_; + + Mat extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift_; + std::vector almost_dist2weight_; + + void calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; +}; + +inline int getNearestPowerOf2(int value) +{ + int p = 0; + while( 1 << p < value) ++p; + return p; +} + +template +FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( + const cv::Mat& src, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const float h) : src_(src), dst_(dst) +{ + CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b + + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + copyMakeBorder(src_, extended_src_, + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + + const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255; + fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + + CV_Assert(template_window_size_ <= 46340 ); // sqrt(INT_MAX) + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq); + double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq; + + int max_dist = 255 * 255 * sizeof(T); + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight_.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) + weight = 0; + + almost_dist2weight_[almost_dist] = weight; + } + CV_Assert(almost_dist2weight_[0] == fixed_point_mult_); + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(src_.size(), src_.type()); + } +} + +template +void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + Array2d dist_sums(search_window_size_, search_window_size_); + + // for lazy calc optimization + Array3d col_dist_sums(template_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < src_.cols; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = dist_sums.row_ptr(y); + + int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); + + int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); + + const T* b_up_ptr = + extended_src_.ptr(start_by - template_window_half_size_ - 1 + y); + + const T* b_down_ptr = + extended_src_.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = + up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[3]; + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { + estimation[channel_num] = 0; + } + + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = extended_src_.ptr(border_size_ + search_window_y + y); + int* dist_sums_row = dist_sums.row_ptr(y); + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_; + + int weight = almost_dist2weight_[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) + estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum/2) / weights_sum; + + dst_.at(i,j) = saturateCastFromArray(estimation); + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int j = 0; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + int dist = calcDist(extended_src_, + border_size_ + i + ty, border_size_ + j + tx, + border_size_ + start_y + ty, border_size_ + start_x + tx); + + dist_sums[y][x] += dist; + col_dist_sums[tx + template_window_half_size_][y][x] += dist; + } + } + + up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; + + col_dist_sums[new_last_col_num][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + col_dist_sums[new_last_col_num][y][x] += + calcDist(extended_src_, ay + ty, ax, by + ty, bx); + } + + dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; + + up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x]; + } + } +} + +#endif diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp new file mode 100644 index 0000000000..978f3170c7 --- /dev/null +++ b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp @@ -0,0 +1,115 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ + +using namespace cv; + +template static inline int calcDist(const T a, const T b); + +template <> inline int calcDist(const uchar a, const uchar b) { + return (a-b) * (a-b); +} + +template <> inline int calcDist(const Vec2b a, const Vec2b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); +} + +template <> inline int calcDist(const Vec3b a, const Vec3b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); +} + +template static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { + const T a = m.at(i1, j1); + const T b = m.at(i2, j2); + return calcDist(a,b); +} + +template static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { + return calcDist(a_down,b_down) - calcDist(a_up, b_up); +} + +template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { + int A = a_down - b_down; + int B = a_up - b_up; + return (A-B)*(A+B); +} + +template static inline void incWithWeight(int* estimation, int weight, T p); + +template <> inline void incWithWeight(int* estimation, int weight, uchar p) { + estimation[0] += weight * p; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; + estimation[2] += weight * p[2]; +} + +template static inline T saturateCastFromArray(int* estimation); + +template <> inline uchar saturateCastFromArray(int* estimation) { + return saturate_cast(estimation[0]); +} + +template <> inline Vec2b saturateCastFromArray(int* estimation) { + Vec2b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + return res; +} + +template <> inline Vec3b saturateCastFromArray(int* estimation) { + Vec3b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + res[2] = saturate_cast(estimation[2]); + return res; +} + +#endif diff --git a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp new file mode 100644 index 0000000000..ee7d3bc7fa --- /dev/null +++ b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -0,0 +1,383 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace cv; + +template +struct FastNlMeansMultiDenoisingInvoker { + public: + FastNlMeansMultiDenoisingInvoker( + const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, + Mat& dst, int template_window_size, int search_window_size, const float h); + + void operator() (const BlockedRange& range) const; + + private: + void operator= (const FastNlMeansMultiDenoisingInvoker&); + + int rows_; + int cols_; + + Mat& dst_; + + std::vector extended_srcs_; + Mat main_extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + int temporal_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + int temporal_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift; + std::vector almost_dist2weight; + + void calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; +}; + +template +FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( + const std::vector& srcImgs, + int imgToDenoiseIndex, + int temporalWindowSize, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const float h) : dst_(dst), extended_srcs_(srcImgs.size()) +{ + CV_Assert(srcImgs.size() > 0); + CV_Assert(srcImgs[0].channels() == sizeof(T)); + + rows_ = srcImgs[0].rows; + cols_ = srcImgs[0].cols; + + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + temporal_window_half_size_ = temporalWindowSize / 2; + + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + temporal_window_size_ = temporal_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + for (int i = 0; i < temporal_window_size_; i++) { + copyMakeBorder( + srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i], + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + } + main_extended_src_ = extended_srcs_[temporal_window_half_size_]; + + const int max_estimate_sum_value = + temporal_window_size_ * search_window_size_ * search_window_size_ * 255; + + fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift = 0; + while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { + almost_template_window_size_sq_bin_shift++; + } + + int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; + double almost_dist2actual_dist_multiplier = + ((double) almost_template_window_size_sq) / template_window_size_sq; + + int max_dist = 255 * 255 * sizeof(T); + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { + weight = 0; + } + + almost_dist2weight[almost_dist] = weight; + } + CV_Assert(almost_dist2weight[0] == fixed_point_mult_); + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); + } +} + +template +void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + Array3d dist_sums(temporal_window_size_, search_window_size_, search_window_size_); + + // for lazy calc optimization + Array4d col_dist_sums( + template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + + Array4d up_col_dist_sums( + cols_, temporal_window_size_, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < cols_; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = main_extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = main_extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + Array2d cur_dist_sums = dist_sums[d]; + Array2d cur_col_dist_sums = col_dist_sums[first_col_num][d]; + Array2d cur_up_col_dist_sums = up_col_dist_sums[j][d]; + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = cur_dist_sums.row_ptr(y); + + int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); + + int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); + + const T* b_up_ptr = + cur_extended_src.ptr(start_by - template_window_half_size_ - 1 + y); + const T* b_down_ptr = + cur_extended_src.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[3]; + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { + estimation[channel_num] = 0; + } + for (int d = 0; d < temporal_window_size_; d++) { + const Mat& esrc_d = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = esrc_d.ptr(border_size_ + search_window_y + y); + + int* dist_sums_row = dist_sums.row_ptr(d, y); + + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; + + int weight = almost_dist2weight[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + } + + for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) + estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum / 2) / weights_sum; + + dst_.at(i,j) = saturateCastFromArray(estimation); + + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int j = 0; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][d][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + int* dist_sums_ptr = &dist_sums[d][y][x]; + int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; + int col_dist_sums_step = col_dist_sums.step_size(0); + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + int dist = calcDist( + main_extended_src_.at( + border_size_ + i + ty, border_size_ + j + tx), + cur_extended_src.at( + border_size_ + start_y + ty, border_size_ + start_x + tx) + ); + + *dist_sums_ptr += dist; + *col_dist_sums_ptr += dist; + } + col_dist_sums_ptr += col_dist_sums_step; + } + + up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; + } + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; + + col_dist_sums[new_last_col_num][d][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + + int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + *col_dist_sums_ptr += + calcDist( + main_extended_src_.at(ay + ty, ax), + cur_extended_src.at(by + ty, bx) + ); + } + + dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; + + up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; + } + } + } +} + +#endif diff --git a/modules/optim/src/inpaint.cpp b/modules/optim/src/inpaint.cpp new file mode 100644 index 0000000000..ec91e3c1bf --- /dev/null +++ b/modules/optim/src/inpaint.cpp @@ -0,0 +1,817 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* //////////////////////////////////////////////////////////////////// +// +// Geometrical transforms on images and matrices: rotation, zoom etc. +// +// */ + +#include "precomp.hpp" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/photo/photo_c.h" + +#undef CV_MAT_ELEM_PTR_FAST +#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ + ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) + +inline float +min4( float a, float b, float c, float d ) +{ + a = MIN(a,b); + c = MIN(c,d); + return MIN(a,c); +} + +#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c)) +#define KNOWN 0 //known outside narrow band +#define BAND 1 //narrow band (known) +#define INSIDE 2 //unknown +#define CHANGE 3 //servise + +typedef struct CvHeapElem +{ + float T; + int i,j; + struct CvHeapElem* prev; + struct CvHeapElem* next; +} +CvHeapElem; + + +class CvPriorityQueueFloat +{ +protected: + CvHeapElem *mem,*empty,*head,*tail; + int num,in; + +public: + bool Init( const CvMat* f ) + { + int i,j; + for( i = num = 0; i < f->rows; i++ ) + { + for( j = 0; j < f->cols; j++ ) + num += CV_MAT_ELEM(*f,uchar,i,j)!=0; + } + if (num<=0) return false; + mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem)); + if (mem==NULL) return false; + + head = mem; + head->i = head->j = -1; + head->prev = NULL; + head->next = mem+1; + head->T = -FLT_MAX; + empty = mem+1; + for (i=1; i<=num; i++) { + mem[i].prev = mem+i-1; + mem[i].next = mem+i+1; + mem[i].i = -1; + mem[i].T = FLT_MAX; + } + tail = mem+i; + tail->i = tail->j = -1; + tail->prev = mem+i-1; + tail->next = NULL; + tail->T = FLT_MAX; + return true; + } + + bool Add(const CvMat* f) { + int i,j; + for (i=0; irows; i++) { + for (j=0; jcols; j++) { + if (CV_MAT_ELEM(*f,uchar,i,j)!=0) { + if (!Push(i,j,0)) return false; + } + } + } + return true; + } + + bool Push(int i, int j, float T) { + CvHeapElem *tmp=empty,*add=empty; + if (empty==tail) return false; + while (tmp->prev->T>T) tmp = tmp->prev; + if (tmp!=empty) { + add->prev->next = add->next; + add->next->prev = add->prev; + empty = add->next; + add->prev = tmp->prev; + add->next = tmp; + add->prev->next = add; + add->next->prev = add; + } else { + empty = empty->next; + } + add->i = i; + add->j = j; + add->T = T; + in++; + // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in); + return true; + } + + bool Pop(int *i, int *j) { + CvHeapElem *tmp=head->next; + if (empty==tmp) return false; + *i = tmp->i; + *j = tmp->j; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; + tmp->prev = empty->prev; + tmp->next = empty; + tmp->prev->next = tmp; + tmp->next->prev = tmp; + empty = tmp; + in--; + // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); + return true; + } + + bool Pop(int *i, int *j, float *T) { + CvHeapElem *tmp=head->next; + if (empty==tmp) return false; + *i = tmp->i; + *j = tmp->j; + *T = tmp->T; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; + tmp->prev = empty->prev; + tmp->next = empty; + tmp->prev->next = tmp; + tmp->next->prev = tmp; + empty = tmp; + in--; + // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); + return true; + } + + CvPriorityQueueFloat(void) { + num=in=0; + mem=empty=head=tail=NULL; + } + + ~CvPriorityQueueFloat(void) + { + cvFree( &mem ); + } +}; + +inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) { + return v1.x*v2.x+v1.y*v2.y; +} + +inline float VectorLength(CvPoint2D32f v1) { + return v1.x*v1.x+v1.y*v1.y; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +//HEAP::iterator Heap_Iterator; +//HEAP Heap; + +static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t) +{ + double sol, a11, a22, m12; + a11=CV_MAT_ELEM(*t,float,i1,j1); + a22=CV_MAT_ELEM(*t,float,i2,j2); + m12=MIN(a11,a22); + + if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE ) + if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) + if( fabs(a11-a22) >= 1.0 ) + sol = 1+m12; + else + sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5; + else + sol = 1+a11; + else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) + sol = 1+a22; + else + sol = 1+m12; + + return (float)sol; +} + +///////////////////////////////////////////////////////////////////////////////////// + + +static void +icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) { + int i, j, ii = 0, jj = 0, q; + float dist; + + while (Heap->Pop(&ii,&jj)) { + + unsigned known=(negate)?CHANGE:KNOWN; + CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known; + + for (q=0; q<4; q++) { + i=0; j=0; + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else {i=ii; j=jj+1;} + if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + if (negate) { + for (i=0; irows; i++) { + for(j=0; jcols; j++) { + if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) { + CV_MAT_ELEM(*f,uchar,i,j) = KNOWN; + CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j); + } + } + } + } +} + + +static void +icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) { + int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; + float dist; + + if (CV_MAT_CN(out->type)==3) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=2; color++) { + CvPoint2D32f gradI,gradT,r; + float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; + + if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; + } else { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); + } else { + gradT.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; + } else { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); + } else { + gradT.y=0; + } + } + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y = (float)(i-k); + r.x = (float)(j-l); + + dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r)))); + lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); + + dir=VectorScalMult(r,gradT); + if (fabs(dir)<=0.01) dir=0.000001f; + w = (float)fabs(dst*lev*dir); + + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; + } else { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; + } else { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); + } else { + gradI.y=0; + } + } + Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); + Jx -= (float)w * (float)(gradI.x*r.x); + Jy -= (float)w * (float)(gradI.y*r.y); + s += w; + } + } + } + } + sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); + { + CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast(sat); + } + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } else if (CV_MAT_CN(out->type)==1) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=0; color++) { + CvPoint2D32f gradI,gradT,r; + float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; + + if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; + } else { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { + gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); + } else { + gradT.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; + } else { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { + gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); + } else { + gradT.y=0; + } + } + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y = (float)(i-k); + r.x = (float)(j-l); + + dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r)))); + lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); + + dir=VectorScalMult(r,gradT); + if (fabs(dir)<=0.01) dir=0.000001f; + w = (float)fabs(dst*lev*dir); + + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; + } else { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1))); + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; + } else { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm))); + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); + } else { + gradI.y=0; + } + } + Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); + Jx -= (float)w * (float)(gradI.x*r.x); + Jy -= (float)w * (float)(gradI.y*r.y); + s += w; + } + } + } + } + sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); + { + CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast(sat); + } + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + } +} + + +static void +icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) { + int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; + float dist; + + if (CV_MAT_CN(out->type)==3) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + for (color=0; color<=2; color++) { + CvPoint2D32f gradI,r; + float Ia=0,s=1.0e-20f,w,dst,dir; + + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==f->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==f->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y=(float)(k-i); + r.x=(float)(l-j); + + dst = 1/(VectorLength(r)*VectorLength(r)+1); + + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+ + abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); + } else { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+ + abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); + } else { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; + } else { + gradI.y=0; + } + } + + gradI.x=-gradI.x; + dir=VectorScalMult(r,gradI); + + if (fabs(dir)<=0.01) { + dir=0.000001f; + } else { + dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); + } + w = dst*dir; + Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); + s += w; + } + } + } + } + CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast((double)Ia/s); + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } else if (CV_MAT_CN(out->type)==1) { + + while (Heap->Pop(&ii,&jj)) { + + CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; + for(q=0; q<4; q++) { + if (q==0) {i=ii-1; j=jj;} + else if(q==1) {i=ii; j=jj-1;} + else if(q==2) {i=ii+1; j=jj;} + else if(q==3) {i=ii; j=jj+1;} + if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; + + if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { + dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), + FastMarching_solve(i+1,j,i,j-1,f,t), + FastMarching_solve(i-1,j,i,j+1,f,t), + FastMarching_solve(i+1,j,i,j+1,f,t)); + CV_MAT_ELEM(*t,float,i,j) = dist; + + { + CvPoint2D32f gradI,r; + float Ia=0,s=1.0e-20f,w,dst,dir; + + for (k=i-range; k<=i+range; k++) { + int km=k-1+(k==1),kp=k-1-(k==t->rows-2); + for (l=j-range; l<=j+range; l++) { + int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); + if (k>0&&l>0&&krows-1&&lcols-1) { + if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& + ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { + r.y=(float)(i-k); + r.x=(float)(j-l); + + dst = 1/(VectorLength(r)*VectorLength(r)+1); + + if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+ + abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); + } else { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { + gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; + } else { + gradI.x=0; + } + } + if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+ + abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1))); + } else { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f; + } + } else { + if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { + gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; + } else { + gradI.y=0; + } + } + + gradI.x=-gradI.x; + dir=VectorScalMult(r,gradI); + + if (fabs(dir)<=0.01) { + dir=0.000001f; + } else { + dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); + } + w = dst*dir; + Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); + s += w; + } + } + } + } + CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast((double)Ia/s); + } + + CV_MAT_ELEM(*f,uchar,i,j) = BAND; + Heap->Push(i,j,dist); + } + } + } + + } +} + +#define SET_BORDER1_C1(image,type,value) {\ + int i,j;\ + for(j=0; jcols; j++) {\ + CV_MAT_ELEM(*image,type,0,j) = value;\ + }\ + for (i=1; irows-1; i++) {\ + CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\ + }\ + for(j=0; jcols; j++) {\ + CV_MAT_ELEM(*image,type,erows-1,j) = value;\ + }\ + } + +#define COPY_MASK_BORDER1_C1(src,dst,type) {\ + int i,j;\ + for (i=0; irows; i++) {\ + for(j=0; jcols; j++) {\ + if (CV_MAT_ELEM(*src,type,i,j)!=0)\ + CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\ + }\ + }\ + } + +namespace cv { +template<> void cv::Ptr::delete_obj() +{ + cvReleaseStructuringElement(&obj); +} +} + +void +cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, + double inpaintRange, int flags ) +{ + cv::Ptr mask, band, f, t, out; + cv::Ptr Heap, Out; + cv::Ptr el_cross, el_range; + + CvMat input_hdr, mask_hdr, output_hdr; + CvMat* input_img, *inpaint_mask, *output_img; + int range=cvRound(inpaintRange); + int erows, ecols; + + input_img = cvGetMat( _input_img, &input_hdr ); + inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr ); + output_img = cvGetMat( _output_img, &output_hdr ); + + if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask)) + CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" ); + + if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 && + CV_MAT_TYPE(input_img->type) != CV_8UC3) || + !CV_ARE_TYPES_EQ(input_img,output_img) ) + CV_Error( CV_StsUnsupportedFormat, + "Only 8-bit 1-channel and 3-channel input/output images are supported" ); + + if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) + CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); + + range = MAX(range,1); + range = MIN(range,100); + + ecols = input_img->cols + 2; + erows = input_img->rows + 2; + + f = cvCreateMat(erows, ecols, CV_8UC1); + t = cvCreateMat(erows, ecols, CV_32FC1); + band = cvCreateMat(erows, ecols, CV_8UC1); + mask = cvCreateMat(erows, ecols, CV_8UC1); + el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL); + + cvCopy( input_img, output_img ); + cvSet(mask,cvScalar(KNOWN,0,0,0)); + COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); + SET_BORDER1_C1(mask,uchar,0); + cvSet(f,cvScalar(KNOWN,0,0,0)); + cvSet(t,cvScalar(1.0e6f,0,0,0)); + cvDilate(mask,band,el_cross,1); // image with narrow band + Heap=new CvPriorityQueueFloat; + if (!Heap->Init(band)) + return; + cvSub(band,mask,band,NULL); + SET_BORDER1_C1(band,uchar,0); + if (!Heap->Add(band)) + return; + cvSet(f,cvScalar(BAND,0,0,0),band); + cvSet(f,cvScalar(INSIDE,0,0,0),mask); + cvSet(t,cvScalar(0,0,0,0),band); + + if( flags == cv::INPAINT_TELEA ) + { + out = cvCreateMat(erows, ecols, CV_8UC1); + el_range = cvCreateStructuringElementEx(2*range+1,2*range+1, + range,range,CV_SHAPE_RECT,NULL); + cvDilate(mask,out,el_range,1); + cvSub(out,mask,out,NULL); + Out=new CvPriorityQueueFloat; + if (!Out->Init(out)) + return; + if (!Out->Add(band)) + return; + cvSub(out,band,out,NULL); + SET_BORDER1_C1(out,uchar,0); + icvCalcFMM(out,t,Out,true); + icvTeleaInpaintFMM(mask,t,output_img,range,Heap); + } + else if (flags == cv::INPAINT_NS) { + icvNSInpaintFMM(mask,t,output_img,range,Heap); + } else { + CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); + } +} + +void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst, + double inpaintRange, int flags ) +{ + Mat src = _src.getMat(), mask = _mask.getMat(); + _dst.create( src.size(), src.type() ); + CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat(); + cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags ); +} diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp new file mode 100644 index 0000000000..3e0ec42de9 --- /dev/null +++ b/modules/optim/src/precomp.cpp @@ -0,0 +1,44 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/modules/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp new file mode 100644 index 0000000000..60cc99b19d --- /dev/null +++ b/modules/optim/src/precomp.hpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using 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 "opencv2/photo.hpp" +#include "opencv2/core/private.hpp" + +#ifdef HAVE_TEGRA_OPTIMIZATION +#include "opencv2/photo/photo_tegra.hpp" +#endif + +#endif diff --git a/modules/optim/test/test_denoising.cpp b/modules/optim/test/test_denoising.cpp new file mode 100644 index 0000000000..ca4f63f222 --- /dev/null +++ b/modules/optim/test/test_denoising.cpp @@ -0,0 +1,158 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using 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 "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + +//#define DUMP_RESULTS + +#ifdef DUMP_RESULTS +# define DUMP(image, path) imwrite(path, image) +#else +# define DUMP(image, path) +#endif + + +TEST(Photo_DenoisingGrayscale, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + string original_path = folder + "lena_noised_gaussian_sigma=10.png"; + string expected_path = folder + "lena_noised_denoised_grayscale_tw=7_sw=21_h=10.png"; + + Mat original = imread(original_path, IMREAD_GRAYSCALE); + Mat expected = imread(expected_path, IMREAD_GRAYSCALE); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + Mat result; + fastNlMeansDenoising(original, result, 10); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingColored, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + string original_path = folder + "lena_noised_gaussian_sigma=10.png"; + string expected_path = folder + "lena_noised_denoised_lab12_tw=7_sw=21_h=10_h2=10.png"; + + Mat original = imread(original_path, IMREAD_COLOR); + Mat expected = imread(expected_path, IMREAD_COLOR); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + Mat result; + fastNlMeansDenoisingColored(original, result, 10, 10); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingGrayscaleMulti, regression) +{ + const int imgs_count = 3; + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + + string expected_path = folder + "lena_noised_denoised_multi_tw=7_sw=21_h=15.png"; + Mat expected = imread(expected_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + vector original(imgs_count); + for (int i = 0; i < imgs_count; i++) + { + string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); + original[i] = imread(original_path, IMREAD_GRAYSCALE); + ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; + } + + Mat result; + fastNlMeansDenoisingMulti(original, result, imgs_count / 2, imgs_count, 15); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_DenoisingColoredMulti, regression) +{ + const int imgs_count = 3; + string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; + + string expected_path = folder + "lena_noised_denoised_multi_lab12_tw=7_sw=21_h=10_h2=15.png"; + Mat expected = imread(expected_path, IMREAD_COLOR); + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + vector original(imgs_count); + for (int i = 0; i < imgs_count; i++) + { + string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); + original[i] = imread(original_path, IMREAD_COLOR); + ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; + } + + Mat result; + fastNlMeansDenoisingColoredMulti(original, result, imgs_count / 2, imgs_count, 10, 15); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} + +TEST(Photo_White, issue_2646) +{ + cv::Mat img(50, 50, CV_8UC1, cv::Scalar::all(255)); + cv::Mat filtered; + cv::fastNlMeansDenoising(img, filtered); + + int nonWhitePixelsCount = (int)img.total() - cv::countNonZero(filtered == img); + + ASSERT_EQ(0, nonWhitePixelsCount); +} diff --git a/modules/optim/test/test_inpaint.cpp b/modules/optim/test/test_inpaint.cpp new file mode 100644 index 0000000000..3c341b27a0 --- /dev/null +++ b/modules/optim/test/test_inpaint.cpp @@ -0,0 +1,119 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using 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 "test_precomp.hpp" +#include + +using namespace std; +using namespace cv; + +class CV_InpaintTest : public cvtest::BaseTest +{ +public: + CV_InpaintTest(); + ~CV_InpaintTest(); +protected: + void run(int); +}; + +CV_InpaintTest::CV_InpaintTest() +{ +} +CV_InpaintTest::~CV_InpaintTest() {} + +void CV_InpaintTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "inpaint/"; + Mat orig = imread(folder + "orig.png"); + Mat exp1 = imread(folder + "exp1.png"); + Mat exp2 = imread(folder + "exp2.png"); + Mat mask = imread(folder + "mask.png"); + + if (orig.empty() || exp1.empty() || exp2.empty() || mask.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat inv_mask; + mask.convertTo(inv_mask, CV_8UC3, -1.0, 255.0); + + Mat mask1ch; + cv::cvtColor(mask, mask1ch, COLOR_BGR2GRAY); + + Mat test = orig.clone(); + test.setTo(Scalar::all(255), mask1ch); + + Mat res1, res2; + inpaint( test, mask1ch, res1, 5, INPAINT_NS ); + inpaint( test, mask1ch, res2, 5, INPAINT_TELEA ); + + Mat diff1, diff2; + absdiff( orig, res1, diff1 ); + absdiff( orig, res2, diff2 ); + + double n1 = norm(diff1.reshape(1), NORM_INF, inv_mask.reshape(1)); + double n2 = norm(diff2.reshape(1), NORM_INF, inv_mask.reshape(1)); + + if (n1 != 0 || n2 != 0) + { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + return; + } + + absdiff( exp1, res1, diff1 ); + absdiff( exp2, res2, diff2 ); + + n1 = norm(diff1.reshape(1), NORM_INF, mask.reshape(1)); + n2 = norm(diff2.reshape(1), NORM_INF, mask.reshape(1)); + + const int jpeg_thres = 3; + if (n1 > jpeg_thres || n2 > jpeg_thres) + { + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + return; + } + + ts->set_failed_test_info(cvtest::TS::OK); +} + +TEST(Photo_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); } diff --git a/modules/optim/test/test_main.cpp b/modules/optim/test/test_main.cpp new file mode 100644 index 0000000000..6b24993447 --- /dev/null +++ b/modules/optim/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/modules/optim/test/test_precomp.cpp b/modules/optim/test/test_precomp.cpp new file mode 100644 index 0000000000..5956e13e3e --- /dev/null +++ b/modules/optim/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/modules/optim/test/test_precomp.hpp b/modules/optim/test/test_precomp.hpp new file mode 100644 index 0000000000..5b22a1c755 --- /dev/null +++ b/modules/optim/test/test_precomp.hpp @@ -0,0 +1,17 @@ +#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/photo.hpp" +#include "opencv2/highgui.hpp" + +#endif From f2afe64521223e601ec26a89434a993d27a158ac Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Mon, 17 Jun 2013 18:16:30 +0300 Subject: [PATCH 02/22] Starting implement simplex algorithm. --- modules/optim/CMakeLists.txt | 4 +- modules/optim/src/arrays.hpp | 161 ---- modules/optim/src/denoising.cpp | 242 ------ .../src/fast_nlmeans_denoising_invoker.hpp | 334 ------- ...fast_nlmeans_denoising_invoker_commons.hpp | 115 --- .../fast_nlmeans_multi_denoising_invoker.hpp | 383 -------- modules/optim/src/inpaint.cpp | 817 ------------------ modules/optim/src/lpsolver.cpp | 45 + modules/optim/src/precomp.cpp | 44 - modules/optim/src/precomp.hpp | 53 -- 10 files changed, 47 insertions(+), 2151 deletions(-) delete mode 100644 modules/optim/src/arrays.hpp delete mode 100644 modules/optim/src/denoising.cpp delete mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker.hpp delete mode 100644 modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp delete mode 100644 modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp delete mode 100644 modules/optim/src/inpaint.cpp create mode 100644 modules/optim/src/lpsolver.cpp delete mode 100644 modules/optim/src/precomp.cpp delete mode 100644 modules/optim/src/precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index 08a72ea928..b5de99de0d 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,2 +1,2 @@ -set(the_description "Computational Photography") -ocv_define_module(photo opencv_imgproc) +set(the_description "Generic optimization") +ocv_define_module(optim) diff --git a/modules/optim/src/arrays.hpp b/modules/optim/src/arrays.hpp deleted file mode 100644 index ae01e9af82..0000000000 --- a/modules/optim/src/arrays.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_DENOISING_ARRAYS_HPP__ -#define __OPENCV_DENOISING_ARRAYS_HPP__ - -template struct Array2d { - T* a; - int n1,n2; - bool needToDeallocArray; - - Array2d(const Array2d& array2d): - a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false) - { - if (array2d.needToDeallocArray) { - // copy constructor for self allocating arrays not supported - throw new std::exception(); - } - } - - Array2d(T* _a, int _n1, int _n2): - a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {} - - Array2d(int _n1, int _n2): - n1(_n1), n2(_n2), needToDeallocArray(true) - { - a = new T[n1*n2]; - } - - ~Array2d() { - if (needToDeallocArray) { - delete[] a; - } - } - - T* operator [] (int i) { - return a + i*n2; - } - - inline T* row_ptr(int i) { - return (*this)[i]; - } -}; - -template struct Array3d { - T* a; - int n1,n2,n3; - bool needToDeallocArray; - - Array3d(T* _a, int _n1, int _n2, int _n3): - a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {} - - Array3d(int _n1, int _n2, int _n3): - n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true) - { - a = new T[n1*n2*n3]; - } - - ~Array3d() { - if (needToDeallocArray) { - delete[] a; - } - } - - Array2d operator [] (int i) { - Array2d array2d(a + i*n2*n3, n2, n3); - return array2d; - } - - inline T* row_ptr(int i1, int i2) { - return a + i1*n2*n3 + i2*n3; - } -}; - -template struct Array4d { - T* a; - int n1,n2,n3,n4; - bool needToDeallocArray; - int steps[4]; - - void init_steps() { - steps[0] = n2*n3*n4; - steps[1] = n3*n4; - steps[2] = n4; - steps[3] = 1; - } - - Array4d(T* _a, int _n1, int _n2, int _n3, int _n4): - a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false) - { - init_steps(); - } - - Array4d(int _n1, int _n2, int _n3, int _n4): - n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true) - { - a = new T[n1*n2*n3*n4]; - init_steps(); - } - - ~Array4d() { - if (needToDeallocArray) { - delete[] a; - } - } - - Array3d operator [] (int i) { - Array3d array3d(a + i*n2*n3*n4, n2, n3, n4); - return array3d; - } - - inline T* row_ptr(int i1, int i2, int i3) { - return a + i1*n2*n3*n4 + i2*n3*n4 + i3*n4; - } - - inline int step_size(int dimension) { - return steps[dimension]; - } -}; - -#endif - - diff --git a/modules/optim/src/denoising.cpp b/modules/optim/src/denoising.cpp deleted file mode 100644 index 4d3e6c8f94..0000000000 --- a/modules/optim/src/denoising.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/imgproc.hpp" -#include "fast_nlmeans_denoising_invoker.hpp" -#include "fast_nlmeans_multi_denoising_invoker.hpp" - -void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h, - int templateWindowSize, int searchWindowSize) -{ - Mat src = _src.getMat(); - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - -#ifdef HAVE_TEGRA_OPTIMIZATION - if(tegra::fastNlMeansDenoising(src, dst, h, templateWindowSize, searchWindowSize)) - return; -#endif - - switch (src.type()) { - case CV_8U: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC2: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC3: - parallel_for(cv::BlockedRange(0, src.rows), - FastNlMeansDenoisingInvoker( - src, dst, templateWindowSize, searchWindowSize, h)); - break; - default: - CV_Error(Error::StsBadArg, - "Unsupported image format! Only CV_8UC1, CV_8UC2 and CV_8UC3 are supported"); - } -} - -void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst, - float h, float hForColorComponents, - int templateWindowSize, int searchWindowSize) -{ - Mat src = _src.getMat(); - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - - if (src.type() != CV_8UC3) { - CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3!"); - return; - } - - Mat src_lab; - cvtColor(src, src_lab, COLOR_LBGR2Lab); - - Mat l(src.size(), CV_8U); - Mat ab(src.size(), CV_8UC2); - Mat l_ab[] = { l, ab }; - int from_to[] = { 0,0, 1,1, 2,2 }; - mixChannels(&src_lab, 1, l_ab, 2, from_to, 3); - - fastNlMeansDenoising(l, l, h, templateWindowSize, searchWindowSize); - fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize); - - Mat l_ab_denoised[] = { l, ab }; - Mat dst_lab(src.size(), src.type()); - mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); - - cvtColor(dst_lab, dst, COLOR_Lab2LBGR); -} - -static void fastNlMeansDenoisingMultiCheckPreconditions( - const std::vector& srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - int templateWindowSize, int searchWindowSize) -{ - int src_imgs_size = (int)srcImgs.size(); - if (src_imgs_size == 0) { - CV_Error(Error::StsBadArg, "Input images vector should not be empty!"); - } - - if (temporalWindowSize % 2 == 0 || - searchWindowSize % 2 == 0 || - templateWindowSize % 2 == 0) { - CV_Error(Error::StsBadArg, "All windows sizes should be odd!"); - } - - int temporalWindowHalfSize = temporalWindowSize / 2; - if (imgToDenoiseIndex - temporalWindowHalfSize < 0 || - imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size) - { - CV_Error(Error::StsBadArg, - "imgToDenoiseIndex and temporalWindowSize " - "should be choosen corresponding srcImgs size!"); - } - - for (int i = 1; i < src_imgs_size; i++) { - if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type()) { - CV_Error(Error::StsBadArg, "Input images should have the same size and type!"); - } - } -} - -void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h, int templateWindowSize, int searchWindowSize) -{ - std::vector srcImgs; - _srcImgs.getMatVector(srcImgs); - - fastNlMeansDenoisingMultiCheckPreconditions( - srcImgs, imgToDenoiseIndex, - temporalWindowSize, templateWindowSize, searchWindowSize - ); - _dst.create(srcImgs[0].size(), srcImgs[0].type()); - Mat dst = _dst.getMat(); - - switch (srcImgs[0].type()) { - case CV_8U: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC2: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - case CV_8UC3: - parallel_for(cv::BlockedRange(0, srcImgs[0].rows), - FastNlMeansMultiDenoisingInvoker( - srcImgs, imgToDenoiseIndex, temporalWindowSize, - dst, templateWindowSize, searchWindowSize, h)); - break; - default: - CV_Error(Error::StsBadArg, - "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); - } -} - -void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputArray _dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h, float hForColorComponents, - int templateWindowSize, int searchWindowSize) -{ - std::vector srcImgs; - _srcImgs.getMatVector(srcImgs); - - fastNlMeansDenoisingMultiCheckPreconditions( - srcImgs, imgToDenoiseIndex, - temporalWindowSize, templateWindowSize, searchWindowSize - ); - - _dst.create(srcImgs[0].size(), srcImgs[0].type()); - Mat dst = _dst.getMat(); - - int src_imgs_size = (int)srcImgs.size(); - - if (srcImgs[0].type() != CV_8UC3) { - CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!"); - return; - } - - int from_to[] = { 0,0, 1,1, 2,2 }; - - // TODO convert only required images - std::vector src_lab(src_imgs_size); - std::vector l(src_imgs_size); - std::vector ab(src_imgs_size); - for (int i = 0; i < src_imgs_size; i++) { - src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3); - l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1); - ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2); - cvtColor(srcImgs[i], src_lab[i], COLOR_LBGR2Lab); - - Mat l_ab[] = { l[i], ab[i] }; - mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3); - } - - Mat dst_l; - Mat dst_ab; - - fastNlMeansDenoisingMulti( - l, dst_l, imgToDenoiseIndex, temporalWindowSize, - h, templateWindowSize, searchWindowSize); - - fastNlMeansDenoisingMulti( - ab, dst_ab, imgToDenoiseIndex, temporalWindowSize, - hForColorComponents, templateWindowSize, searchWindowSize); - - Mat l_ab_denoised[] = { dst_l, dst_ab }; - Mat dst_lab(srcImgs[0].size(), srcImgs[0].type()); - mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); - - cvtColor(dst_lab, dst, COLOR_Lab2LBGR); -} - - diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker.hpp deleted file mode 100644 index 232dba88da..0000000000 --- a/modules/optim/src/fast_nlmeans_denoising_invoker.hpp +++ /dev/null @@ -1,334 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ -#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ - -#include "precomp.hpp" -#include - -#include "fast_nlmeans_denoising_invoker_commons.hpp" -#include "arrays.hpp" - -using namespace cv; - -template -struct FastNlMeansDenoisingInvoker { - public: - FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, - int template_window_size, int search_window_size, const float h); - - void operator() (const BlockedRange& range) const; - - private: - void operator= (const FastNlMeansDenoisingInvoker&); - - const Mat& src_; - Mat& dst_; - - Mat extended_src_; - int border_size_; - - int template_window_size_; - int search_window_size_; - - int template_window_half_size_; - int search_window_half_size_; - - int fixed_point_mult_; - int almost_template_window_size_sq_bin_shift_; - std::vector almost_dist2weight_; - - void calcDistSumsForFirstElementInRow( - int i, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const; - - void calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const; -}; - -inline int getNearestPowerOf2(int value) -{ - int p = 0; - while( 1 << p < value) ++p; - return p; -} - -template -FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( - const cv::Mat& src, - cv::Mat& dst, - int template_window_size, - int search_window_size, - const float h) : src_(src), dst_(dst) -{ - CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b - - template_window_half_size_ = template_window_size / 2; - search_window_half_size_ = search_window_size / 2; - template_window_size_ = template_window_half_size_ * 2 + 1; - search_window_size_ = search_window_half_size_ * 2 + 1; - - border_size_ = search_window_half_size_ + template_window_half_size_; - copyMakeBorder(src_, extended_src_, - border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); - - const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255; - fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; - - // precalc weight for every possible l2 dist between blocks - // additional optimization of precalced weights to replace division(averaging) by binary shift - - CV_Assert(template_window_size_ <= 46340 ); // sqrt(INT_MAX) - int template_window_size_sq = template_window_size_ * template_window_size_; - almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq); - double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq; - - int max_dist = 255 * 255 * sizeof(T); - int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); - almost_dist2weight_.resize(almost_max_dist); - - const double WEIGHT_THRESHOLD = 0.001; - for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { - double dist = almost_dist * almost_dist2actual_dist_multiplier; - int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); - - if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) - weight = 0; - - almost_dist2weight_[almost_dist] = weight; - } - CV_Assert(almost_dist2weight_[0] == fixed_point_mult_); - // additional optimization init end - - if (dst_.empty()) { - dst_ = Mat::zeros(src_.size(), src_.type()); - } -} - -template -void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) const { - int row_from = range.begin(); - int row_to = range.end() - 1; - - Array2d dist_sums(search_window_size_, search_window_size_); - - // for lazy calc optimization - Array3d col_dist_sums(template_window_size_, search_window_size_, search_window_size_); - - int first_col_num = -1; - Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); - - for (int i = row_from; i <= row_to; i++) { - for (int j = 0; j < src_.cols; j++) { - int search_window_y = i - search_window_half_size_; - int search_window_x = j - search_window_half_size_; - - // calc dist_sums - if (j == 0) { - calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); - first_col_num = 0; - - } else { // calc cur dist_sums using previous dist_sums - if (i == row_from) { - calcDistSumsForElementInFirstRow(i, j, first_col_num, - dist_sums, col_dist_sums, up_col_dist_sums); - - } else { - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = - border_size_ + i - search_window_half_size_; - - int start_bx = - border_size_ + j - search_window_half_size_ + template_window_half_size_; - - T a_up = extended_src_.at(ay - template_window_half_size_ - 1, ax); - T a_down = extended_src_.at(ay + template_window_half_size_, ax); - - // copy class member to local variable for optimization - int search_window_size = search_window_size_; - - for (int y = 0; y < search_window_size; y++) { - int* dist_sums_row = dist_sums.row_ptr(y); - - int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); - - int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); - - const T* b_up_ptr = - extended_src_.ptr(start_by - template_window_half_size_ - 1 + y); - - const T* b_down_ptr = - extended_src_.ptr(start_by + template_window_half_size_ + y); - - for (int x = 0; x < search_window_size; x++) { - dist_sums_row[x] -= col_dist_sums_row[x]; - - col_dist_sums_row[x] = - up_col_dist_sums_row[x] + - calcUpDownDist( - a_up, a_down, - b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] - ); - - dist_sums_row[x] += col_dist_sums_row[x]; - - up_col_dist_sums_row[x] = col_dist_sums_row[x]; - - } - } - } - - first_col_num = (first_col_num + 1) % template_window_size_; - } - - // calc weights - int weights_sum = 0; - - int estimation[3]; - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { - estimation[channel_num] = 0; - } - - for (int y = 0; y < search_window_size_; y++) { - const T* cur_row_ptr = extended_src_.ptr(border_size_ + search_window_y + y); - int* dist_sums_row = dist_sums.row_ptr(y); - for (int x = 0; x < search_window_size_; x++) { - int almostAvgDist = - dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_; - - int weight = almost_dist2weight_[almostAvgDist]; - weights_sum += weight; - - T p = cur_row_ptr[border_size_ + search_window_x + x]; - incWithWeight(estimation, weight, p); - } - } - - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) - estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum/2) / weights_sum; - - dst_.at(i,j) = saturateCastFromArray(estimation); - } - } -} - -template -inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow( - int i, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const -{ - int j = 0; - - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[y][x] = 0; - for (int tx = 0; tx < template_window_size_; tx++) { - col_dist_sums[tx][y][x] = 0; - } - - int start_y = i + y - search_window_half_size_; - int start_x = j + x - search_window_half_size_; - - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { - int dist = calcDist(extended_src_, - border_size_ + i + ty, border_size_ + j + tx, - border_size_ + start_y + ty, border_size_ + start_x + tx); - - dist_sums[y][x] += dist; - col_dist_sums[tx + template_window_half_size_][y][x] += dist; - } - } - - up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; - } - } -} - -template -inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array2d& dist_sums, - Array3d& col_dist_sums, - Array3d& up_col_dist_sums) const -{ - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = border_size_ + i - search_window_half_size_; - int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; - - int new_last_col_num = first_col_num; - - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; - - col_dist_sums[new_last_col_num][y][x] = 0; - int by = start_by + y; - int bx = start_bx + x; - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - col_dist_sums[new_last_col_num][y][x] += - calcDist(extended_src_, ay + ty, ax, by + ty, bx); - } - - dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; - - up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x]; - } - } -} - -#endif diff --git a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp deleted file mode 100644 index 978f3170c7..0000000000 --- a/modules/optim/src/fast_nlmeans_denoising_invoker_commons.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ -#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ - -using namespace cv; - -template static inline int calcDist(const T a, const T b); - -template <> inline int calcDist(const uchar a, const uchar b) { - return (a-b) * (a-b); -} - -template <> inline int calcDist(const Vec2b a, const Vec2b b) { - return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); -} - -template <> inline int calcDist(const Vec3b a, const Vec3b b) { - return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); -} - -template static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { - const T a = m.at(i1, j1); - const T b = m.at(i2, j2); - return calcDist(a,b); -} - -template static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { - return calcDist(a_down,b_down) - calcDist(a_up, b_up); -} - -template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { - int A = a_down - b_down; - int B = a_up - b_up; - return (A-B)*(A+B); -} - -template static inline void incWithWeight(int* estimation, int weight, T p); - -template <> inline void incWithWeight(int* estimation, int weight, uchar p) { - estimation[0] += weight * p; -} - -template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { - estimation[0] += weight * p[0]; - estimation[1] += weight * p[1]; -} - -template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { - estimation[0] += weight * p[0]; - estimation[1] += weight * p[1]; - estimation[2] += weight * p[2]; -} - -template static inline T saturateCastFromArray(int* estimation); - -template <> inline uchar saturateCastFromArray(int* estimation) { - return saturate_cast(estimation[0]); -} - -template <> inline Vec2b saturateCastFromArray(int* estimation) { - Vec2b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); - return res; -} - -template <> inline Vec3b saturateCastFromArray(int* estimation) { - Vec3b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); - res[2] = saturate_cast(estimation[2]); - return res; -} - -#endif diff --git a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp deleted file mode 100644 index ee7d3bc7fa..0000000000 --- a/modules/optim/src/fast_nlmeans_multi_denoising_invoker.hpp +++ /dev/null @@ -1,383 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ -#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ - -#include "precomp.hpp" -#include - -#include "fast_nlmeans_denoising_invoker_commons.hpp" -#include "arrays.hpp" - -using namespace cv; - -template -struct FastNlMeansMultiDenoisingInvoker { - public: - FastNlMeansMultiDenoisingInvoker( - const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, - Mat& dst, int template_window_size, int search_window_size, const float h); - - void operator() (const BlockedRange& range) const; - - private: - void operator= (const FastNlMeansMultiDenoisingInvoker&); - - int rows_; - int cols_; - - Mat& dst_; - - std::vector extended_srcs_; - Mat main_extended_src_; - int border_size_; - - int template_window_size_; - int search_window_size_; - int temporal_window_size_; - - int template_window_half_size_; - int search_window_half_size_; - int temporal_window_half_size_; - - int fixed_point_mult_; - int almost_template_window_size_sq_bin_shift; - std::vector almost_dist2weight; - - void calcDistSumsForFirstElementInRow( - int i, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const; - - void calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const; -}; - -template -FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( - const std::vector& srcImgs, - int imgToDenoiseIndex, - int temporalWindowSize, - cv::Mat& dst, - int template_window_size, - int search_window_size, - const float h) : dst_(dst), extended_srcs_(srcImgs.size()) -{ - CV_Assert(srcImgs.size() > 0); - CV_Assert(srcImgs[0].channels() == sizeof(T)); - - rows_ = srcImgs[0].rows; - cols_ = srcImgs[0].cols; - - template_window_half_size_ = template_window_size / 2; - search_window_half_size_ = search_window_size / 2; - temporal_window_half_size_ = temporalWindowSize / 2; - - template_window_size_ = template_window_half_size_ * 2 + 1; - search_window_size_ = search_window_half_size_ * 2 + 1; - temporal_window_size_ = temporal_window_half_size_ * 2 + 1; - - border_size_ = search_window_half_size_ + template_window_half_size_; - for (int i = 0; i < temporal_window_size_; i++) { - copyMakeBorder( - srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i], - border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); - } - main_extended_src_ = extended_srcs_[temporal_window_half_size_]; - - const int max_estimate_sum_value = - temporal_window_size_ * search_window_size_ * search_window_size_ * 255; - - fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; - - // precalc weight for every possible l2 dist between blocks - // additional optimization of precalced weights to replace division(averaging) by binary shift - int template_window_size_sq = template_window_size_ * template_window_size_; - almost_template_window_size_sq_bin_shift = 0; - while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { - almost_template_window_size_sq_bin_shift++; - } - - int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; - double almost_dist2actual_dist_multiplier = - ((double) almost_template_window_size_sq) / template_window_size_sq; - - int max_dist = 255 * 255 * sizeof(T); - int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); - almost_dist2weight.resize(almost_max_dist); - - const double WEIGHT_THRESHOLD = 0.001; - for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { - double dist = almost_dist * almost_dist2actual_dist_multiplier; - int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); - - if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { - weight = 0; - } - - almost_dist2weight[almost_dist] = weight; - } - CV_Assert(almost_dist2weight[0] == fixed_point_mult_); - // additional optimization init end - - if (dst_.empty()) { - dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); - } -} - -template -void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) const { - int row_from = range.begin(); - int row_to = range.end() - 1; - - Array3d dist_sums(temporal_window_size_, search_window_size_, search_window_size_); - - // for lazy calc optimization - Array4d col_dist_sums( - template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); - - int first_col_num = -1; - - Array4d up_col_dist_sums( - cols_, temporal_window_size_, search_window_size_, search_window_size_); - - for (int i = row_from; i <= row_to; i++) { - for (int j = 0; j < cols_; j++) { - int search_window_y = i - search_window_half_size_; - int search_window_x = j - search_window_half_size_; - - // calc dist_sums - if (j == 0) { - calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); - first_col_num = 0; - - } else { // calc cur dist_sums using previous dist_sums - if (i == row_from) { - calcDistSumsForElementInFirstRow(i, j, first_col_num, - dist_sums, col_dist_sums, up_col_dist_sums); - - } else { - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = - border_size_ + i - search_window_half_size_; - - int start_bx = - border_size_ + j - search_window_half_size_ + template_window_half_size_; - - T a_up = main_extended_src_.at(ay - template_window_half_size_ - 1, ax); - T a_down = main_extended_src_.at(ay + template_window_half_size_, ax); - - // copy class member to local variable for optimization - int search_window_size = search_window_size_; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - Array2d cur_dist_sums = dist_sums[d]; - Array2d cur_col_dist_sums = col_dist_sums[first_col_num][d]; - Array2d cur_up_col_dist_sums = up_col_dist_sums[j][d]; - for (int y = 0; y < search_window_size; y++) { - int* dist_sums_row = cur_dist_sums.row_ptr(y); - - int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); - - int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); - - const T* b_up_ptr = - cur_extended_src.ptr(start_by - template_window_half_size_ - 1 + y); - const T* b_down_ptr = - cur_extended_src.ptr(start_by + template_window_half_size_ + y); - - for (int x = 0; x < search_window_size; x++) { - dist_sums_row[x] -= col_dist_sums_row[x]; - - col_dist_sums_row[x] = up_col_dist_sums_row[x] + - calcUpDownDist( - a_up, a_down, - b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] - ); - - dist_sums_row[x] += col_dist_sums_row[x]; - - up_col_dist_sums_row[x] = col_dist_sums_row[x]; - - } - } - } - } - - first_col_num = (first_col_num + 1) % template_window_size_; - } - - // calc weights - int weights_sum = 0; - - int estimation[3]; - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { - estimation[channel_num] = 0; - } - for (int d = 0; d < temporal_window_size_; d++) { - const Mat& esrc_d = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - const T* cur_row_ptr = esrc_d.ptr(border_size_ + search_window_y + y); - - int* dist_sums_row = dist_sums.row_ptr(d, y); - - for (int x = 0; x < search_window_size_; x++) { - int almostAvgDist = - dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; - - int weight = almost_dist2weight[almostAvgDist]; - weights_sum += weight; - - T p = cur_row_ptr[border_size_ + search_window_x + x]; - incWithWeight(estimation, weight, p); - } - } - } - - for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) - estimation[channel_num] = ((unsigned)estimation[channel_num] + weights_sum / 2) / weights_sum; - - dst_.at(i,j) = saturateCastFromArray(estimation); - - } - } -} - -template -inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow( - int i, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const -{ - int j = 0; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[d][y][x] = 0; - for (int tx = 0; tx < template_window_size_; tx++) { - col_dist_sums[tx][d][y][x] = 0; - } - - int start_y = i + y - search_window_half_size_; - int start_x = j + x - search_window_half_size_; - - int* dist_sums_ptr = &dist_sums[d][y][x]; - int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; - int col_dist_sums_step = col_dist_sums.step_size(0); - for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - int dist = calcDist( - main_extended_src_.at( - border_size_ + i + ty, border_size_ + j + tx), - cur_extended_src.at( - border_size_ + start_y + ty, border_size_ + start_x + tx) - ); - - *dist_sums_ptr += dist; - *col_dist_sums_ptr += dist; - } - col_dist_sums_ptr += col_dist_sums_step; - } - - up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; - } - } - } -} - -template -inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow( - int i, - int j, - int first_col_num, - Array3d& dist_sums, - Array4d& col_dist_sums, - Array4d& up_col_dist_sums) const -{ - int ay = border_size_ + i; - int ax = border_size_ + j + template_window_half_size_; - - int start_by = border_size_ + i - search_window_half_size_; - int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; - - int new_last_col_num = first_col_num; - - for (int d = 0; d < temporal_window_size_; d++) { - Mat cur_extended_src = extended_srcs_[d]; - for (int y = 0; y < search_window_size_; y++) { - for (int x = 0; x < search_window_size_; x++) { - dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; - - col_dist_sums[new_last_col_num][d][y][x] = 0; - int by = start_by + y; - int bx = start_bx + x; - - int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; - for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { - *col_dist_sums_ptr += - calcDist( - main_extended_src_.at(ay + ty, ax), - cur_extended_src.at(by + ty, bx) - ); - } - - dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; - - up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; - } - } - } -} - -#endif diff --git a/modules/optim/src/inpaint.cpp b/modules/optim/src/inpaint.cpp deleted file mode 100644 index ec91e3c1bf..0000000000 --- a/modules/optim/src/inpaint.cpp +++ /dev/null @@ -1,817 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective icvers. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -/* //////////////////////////////////////////////////////////////////// -// -// Geometrical transforms on images and matrices: rotation, zoom etc. -// -// */ - -#include "precomp.hpp" -#include "opencv2/imgproc/imgproc_c.h" -#include "opencv2/photo/photo_c.h" - -#undef CV_MAT_ELEM_PTR_FAST -#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \ - ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col)) - -inline float -min4( float a, float b, float c, float d ) -{ - a = MIN(a,b); - c = MIN(c,d); - return MIN(a,c); -} - -#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c)) -#define KNOWN 0 //known outside narrow band -#define BAND 1 //narrow band (known) -#define INSIDE 2 //unknown -#define CHANGE 3 //servise - -typedef struct CvHeapElem -{ - float T; - int i,j; - struct CvHeapElem* prev; - struct CvHeapElem* next; -} -CvHeapElem; - - -class CvPriorityQueueFloat -{ -protected: - CvHeapElem *mem,*empty,*head,*tail; - int num,in; - -public: - bool Init( const CvMat* f ) - { - int i,j; - for( i = num = 0; i < f->rows; i++ ) - { - for( j = 0; j < f->cols; j++ ) - num += CV_MAT_ELEM(*f,uchar,i,j)!=0; - } - if (num<=0) return false; - mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem)); - if (mem==NULL) return false; - - head = mem; - head->i = head->j = -1; - head->prev = NULL; - head->next = mem+1; - head->T = -FLT_MAX; - empty = mem+1; - for (i=1; i<=num; i++) { - mem[i].prev = mem+i-1; - mem[i].next = mem+i+1; - mem[i].i = -1; - mem[i].T = FLT_MAX; - } - tail = mem+i; - tail->i = tail->j = -1; - tail->prev = mem+i-1; - tail->next = NULL; - tail->T = FLT_MAX; - return true; - } - - bool Add(const CvMat* f) { - int i,j; - for (i=0; irows; i++) { - for (j=0; jcols; j++) { - if (CV_MAT_ELEM(*f,uchar,i,j)!=0) { - if (!Push(i,j,0)) return false; - } - } - } - return true; - } - - bool Push(int i, int j, float T) { - CvHeapElem *tmp=empty,*add=empty; - if (empty==tail) return false; - while (tmp->prev->T>T) tmp = tmp->prev; - if (tmp!=empty) { - add->prev->next = add->next; - add->next->prev = add->prev; - empty = add->next; - add->prev = tmp->prev; - add->next = tmp; - add->prev->next = add; - add->next->prev = add; - } else { - empty = empty->next; - } - add->i = i; - add->j = j; - add->T = T; - in++; - // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in); - return true; - } - - bool Pop(int *i, int *j) { - CvHeapElem *tmp=head->next; - if (empty==tmp) return false; - *i = tmp->i; - *j = tmp->j; - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; - tmp->prev = empty->prev; - tmp->next = empty; - tmp->prev->next = tmp; - tmp->next->prev = tmp; - empty = tmp; - in--; - // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); - return true; - } - - bool Pop(int *i, int *j, float *T) { - CvHeapElem *tmp=head->next; - if (empty==tmp) return false; - *i = tmp->i; - *j = tmp->j; - *T = tmp->T; - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; - tmp->prev = empty->prev; - tmp->next = empty; - tmp->prev->next = tmp; - tmp->next->prev = tmp; - empty = tmp; - in--; - // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in); - return true; - } - - CvPriorityQueueFloat(void) { - num=in=0; - mem=empty=head=tail=NULL; - } - - ~CvPriorityQueueFloat(void) - { - cvFree( &mem ); - } -}; - -inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) { - return v1.x*v2.x+v1.y*v2.y; -} - -inline float VectorLength(CvPoint2D32f v1) { - return v1.x*v1.x+v1.y*v1.y; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -//HEAP::iterator Heap_Iterator; -//HEAP Heap; - -static float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t) -{ - double sol, a11, a22, m12; - a11=CV_MAT_ELEM(*t,float,i1,j1); - a22=CV_MAT_ELEM(*t,float,i2,j2); - m12=MIN(a11,a22); - - if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE ) - if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) - if( fabs(a11-a22) >= 1.0 ) - sol = 1+m12; - else - sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5; - else - sol = 1+a11; - else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE ) - sol = 1+a22; - else - sol = 1+m12; - - return (float)sol; -} - -///////////////////////////////////////////////////////////////////////////////////// - - -static void -icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) { - int i, j, ii = 0, jj = 0, q; - float dist; - - while (Heap->Pop(&ii,&jj)) { - - unsigned known=(negate)?CHANGE:KNOWN; - CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known; - - for (q=0; q<4; q++) { - i=0; j=0; - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else {i=ii; j=jj+1;} - if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - if (negate) { - for (i=0; irows; i++) { - for(j=0; jcols; j++) { - if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) { - CV_MAT_ELEM(*f,uchar,i,j) = KNOWN; - CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j); - } - } - } - } -} - - -static void -icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) { - int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; - float dist; - - if (CV_MAT_CN(out->type)==3) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=2; color++) { - CvPoint2D32f gradI,gradT,r; - float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; - - if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; - } else { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); - } else { - gradT.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; - } else { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); - } else { - gradT.y=0; - } - } - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y = (float)(i-k); - r.x = (float)(j-l); - - dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r)))); - lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); - - dir=VectorScalMult(r,gradT); - if (fabs(dir)<=0.01) dir=0.000001f; - w = (float)fabs(dst*lev*dir); - - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; - } else { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; - } else { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); - } else { - gradI.y=0; - } - } - Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); - Jx -= (float)w * (float)(gradI.x*r.x); - Jy -= (float)w * (float)(gradI.y*r.y); - s += w; - } - } - } - } - sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); - { - CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast(sat); - } - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } else if (CV_MAT_CN(out->type)==1) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=0; color++) { - CvPoint2D32f gradI,gradT,r; - float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat; - - if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f; - } else { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) { - gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1))); - } else { - gradT.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f; - } else { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) { - gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j))); - } else { - gradT.y=0; - } - } - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y = (float)(i-k); - r.x = (float)(j-l); - - dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r)))); - lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j)))); - - dir=VectorScalMult(r,gradT); - if (fabs(dir)<=0.01) dir=0.000001f; - w = (float)fabs(dst*lev*dir); - - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; - } else { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1))); - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; - } else { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm))); - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); - } else { - gradI.y=0; - } - } - Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); - Jx -= (float)w * (float)(gradI.x*r.x); - Jy -= (float)w * (float)(gradI.y*r.y); - s += w; - } - } - } - } - sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f)); - { - CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast(sat); - } - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - } -} - - -static void -icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) { - int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0; - float dist; - - if (CV_MAT_CN(out->type)==3) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - for (color=0; color<=2; color++) { - CvPoint2D32f gradI,r; - float Ia=0,s=1.0e-20f,w,dst,dir; - - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==f->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==f->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y=(float)(k-i); - r.x=(float)(l-j); - - dst = 1/(VectorLength(r)*VectorLength(r)+1); - - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+ - abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color))); - } else { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f; - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+ - abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color))); - } else { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f; - } else { - gradI.y=0; - } - } - - gradI.x=-gradI.x; - dir=VectorScalMult(r,gradI); - - if (fabs(dir)<=0.01) { - dir=0.000001f; - } else { - dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); - } - w = dst*dir; - Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)); - s += w; - } - } - } - } - CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = cv::saturate_cast((double)Ia/s); - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } else if (CV_MAT_CN(out->type)==1) { - - while (Heap->Pop(&ii,&jj)) { - - CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN; - for(q=0; q<4; q++) { - if (q==0) {i=ii-1; j=jj;} - else if(q==1) {i=ii; j=jj-1;} - else if(q==2) {i=ii+1; j=jj;} - else if(q==3) {i=ii; j=jj+1;} - if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue; - - if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) { - dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t), - FastMarching_solve(i+1,j,i,j-1,f,t), - FastMarching_solve(i-1,j,i,j+1,f,t), - FastMarching_solve(i+1,j,i,j+1,f,t)); - CV_MAT_ELEM(*t,float,i,j) = dist; - - { - CvPoint2D32f gradI,r; - float Ia=0,s=1.0e-20f,w,dst,dir; - - for (k=i-range; k<=i+range; k++) { - int km=k-1+(k==1),kp=k-1-(k==t->rows-2); - for (l=j-range; l<=j+range; l++) { - int lm=l-1+(l==1),lp=l-1-(l==t->cols-2); - if (k>0&&l>0&&krows-1&&lcols-1) { - if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&& - ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) { - r.y=(float)(i-k); - r.x=(float)(j-l); - - dst = 1/(VectorLength(r)*VectorLength(r)+1); - - if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+ - abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm))); - } else { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) { - gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f; - } else { - gradI.x=0; - } - } - if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+ - abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1))); - } else { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f; - } - } else { - if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) { - gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f; - } else { - gradI.y=0; - } - } - - gradI.x=-gradI.x; - dir=VectorScalMult(r,gradI); - - if (fabs(dir)<=0.01) { - dir=0.000001f; - } else { - dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI))); - } - w = dst*dir; - Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm)); - s += w; - } - } - } - } - CV_MAT_ELEM(*out,uchar,i-1,j-1) = cv::saturate_cast((double)Ia/s); - } - - CV_MAT_ELEM(*f,uchar,i,j) = BAND; - Heap->Push(i,j,dist); - } - } - } - - } -} - -#define SET_BORDER1_C1(image,type,value) {\ - int i,j;\ - for(j=0; jcols; j++) {\ - CV_MAT_ELEM(*image,type,0,j) = value;\ - }\ - for (i=1; irows-1; i++) {\ - CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\ - }\ - for(j=0; jcols; j++) {\ - CV_MAT_ELEM(*image,type,erows-1,j) = value;\ - }\ - } - -#define COPY_MASK_BORDER1_C1(src,dst,type) {\ - int i,j;\ - for (i=0; irows; i++) {\ - for(j=0; jcols; j++) {\ - if (CV_MAT_ELEM(*src,type,i,j)!=0)\ - CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\ - }\ - }\ - } - -namespace cv { -template<> void cv::Ptr::delete_obj() -{ - cvReleaseStructuringElement(&obj); -} -} - -void -cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img, - double inpaintRange, int flags ) -{ - cv::Ptr mask, band, f, t, out; - cv::Ptr Heap, Out; - cv::Ptr el_cross, el_range; - - CvMat input_hdr, mask_hdr, output_hdr; - CvMat* input_img, *inpaint_mask, *output_img; - int range=cvRound(inpaintRange); - int erows, ecols; - - input_img = cvGetMat( _input_img, &input_hdr ); - inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr ); - output_img = cvGetMat( _output_img, &output_hdr ); - - if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask)) - CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" ); - - if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 && - CV_MAT_TYPE(input_img->type) != CV_8UC3) || - !CV_ARE_TYPES_EQ(input_img,output_img) ) - CV_Error( CV_StsUnsupportedFormat, - "Only 8-bit 1-channel and 3-channel input/output images are supported" ); - - if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 ) - CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" ); - - range = MAX(range,1); - range = MIN(range,100); - - ecols = input_img->cols + 2; - erows = input_img->rows + 2; - - f = cvCreateMat(erows, ecols, CV_8UC1); - t = cvCreateMat(erows, ecols, CV_32FC1); - band = cvCreateMat(erows, ecols, CV_8UC1); - mask = cvCreateMat(erows, ecols, CV_8UC1); - el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL); - - cvCopy( input_img, output_img ); - cvSet(mask,cvScalar(KNOWN,0,0,0)); - COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar); - SET_BORDER1_C1(mask,uchar,0); - cvSet(f,cvScalar(KNOWN,0,0,0)); - cvSet(t,cvScalar(1.0e6f,0,0,0)); - cvDilate(mask,band,el_cross,1); // image with narrow band - Heap=new CvPriorityQueueFloat; - if (!Heap->Init(band)) - return; - cvSub(band,mask,band,NULL); - SET_BORDER1_C1(band,uchar,0); - if (!Heap->Add(band)) - return; - cvSet(f,cvScalar(BAND,0,0,0),band); - cvSet(f,cvScalar(INSIDE,0,0,0),mask); - cvSet(t,cvScalar(0,0,0,0),band); - - if( flags == cv::INPAINT_TELEA ) - { - out = cvCreateMat(erows, ecols, CV_8UC1); - el_range = cvCreateStructuringElementEx(2*range+1,2*range+1, - range,range,CV_SHAPE_RECT,NULL); - cvDilate(mask,out,el_range,1); - cvSub(out,mask,out,NULL); - Out=new CvPriorityQueueFloat; - if (!Out->Init(out)) - return; - if (!Out->Add(band)) - return; - cvSub(out,band,out,NULL); - SET_BORDER1_C1(out,uchar,0); - icvCalcFMM(out,t,Out,true); - icvTeleaInpaintFMM(mask,t,output_img,range,Heap); - } - else if (flags == cv::INPAINT_NS) { - icvNSInpaintFMM(mask,t,output_img,range,Heap); - } else { - CV_Error( cv::Error::StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" ); - } -} - -void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst, - double inpaintRange, int flags ) -{ - Mat src = _src.getMat(), mask = _mask.getMat(); - _dst.create( src.size(), src.type() ); - CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat(); - cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags ); -} diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp new file mode 100644 index 0000000000..7fb62e01fc --- /dev/null +++ b/modules/optim/src/lpsolver.cpp @@ -0,0 +1,45 @@ +#include "opencv2/opencv.hpp" + +namespace cv { + namespace optim { + +class Solver : public Algorithm /* Algorithm is base OpenCV class */ +{ + class Function + { + public: + virtual ~Function() {} + virtual double calc(InputArray args) const = 0; + virtual double calc(InputArgs, OutputArray grad) const = 0; + }; + + // could be reused for all the generic algorithms like downhill simplex. + virtual void solve(InputArray x0, OutputArray result) const = 0; + + virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0; + + // more detailed API to be defined later ... +}; + +class LPSolver : public Solver +{ +public: + virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; + // ... +}; + +Ptr createLPSimplexSolver(); + +}} + +/*=============== +Hill climbing solver is more generic one:*/ +/* +class DownhillSolver : public Solver +{ +public: + // various setters and getters, if needed +}; + +Ptr createDownhillSolver(const Ptr& func);*/ diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp deleted file mode 100644 index 3e0ec42de9..0000000000 --- a/modules/optim/src/precomp.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including 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/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp deleted file mode 100644 index 60cc99b19d..0000000000 --- a/modules/optim/src/precomp.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using 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 "opencv2/photo.hpp" -#include "opencv2/core/private.hpp" - -#ifdef HAVE_TEGRA_OPTIMIZATION -#include "opencv2/photo/photo_tegra.hpp" -#endif - -#endif From f41b8b90ffc507a4eba418d1d2790e4bf0962cf6 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 20 Jun 2013 14:54:09 +0300 Subject: [PATCH 03/22] Blank module and first draft of solver API. At this point we have a skeleton of a new module (optim) which can barely compile properly (unlike previous commit). Besides, there is a first draft of solver and lpsolver (linear optimization solver) in this commit. --- modules/optim/CMakeLists.txt | 3 +- modules/optim/doc/denoising.rst | 91 ---------- modules/optim/doc/inpainting.rst | 32 ---- modules/optim/doc/photo.rst | 11 -- .../include/opencv2/{photo.hpp => optim.hpp} | 57 +++---- .../{photo/photo.hpp => optim/optim.hpp} | 2 +- modules/optim/perf/perf_inpaint.cpp | 38 ----- modules/optim/perf/perf_main.cpp | 3 - modules/optim/perf/perf_precomp.cpp | 1 - modules/optim/perf/perf_precomp.hpp | 20 --- modules/optim/src/lpsolver.cpp | 47 +----- modules/optim/src/precomp.cpp | 44 +++++ .../photo/photo_c.h => src/precomp.hpp} | 31 +--- modules/optim/test/test_denoising.cpp | 158 ------------------ modules/optim/test/test_inpaint.cpp | 119 ------------- modules/optim/test/test_main.cpp | 3 - modules/optim/test/test_precomp.cpp | 1 - modules/optim/test/test_precomp.hpp | 17 -- 18 files changed, 83 insertions(+), 595 deletions(-) delete mode 100644 modules/optim/doc/denoising.rst delete mode 100644 modules/optim/doc/inpainting.rst delete mode 100644 modules/optim/doc/photo.rst rename modules/optim/include/opencv2/{photo.hpp => optim.hpp} (59%) rename modules/optim/include/opencv2/{photo/photo.hpp => optim/optim.hpp} (98%) delete mode 100644 modules/optim/perf/perf_inpaint.cpp delete mode 100644 modules/optim/perf/perf_main.cpp delete mode 100644 modules/optim/perf/perf_precomp.cpp delete mode 100644 modules/optim/perf/perf_precomp.hpp create mode 100644 modules/optim/src/precomp.cpp rename modules/optim/{include/opencv2/photo/photo_c.h => src/precomp.hpp} (77%) delete mode 100644 modules/optim/test/test_denoising.cpp delete mode 100644 modules/optim/test/test_inpaint.cpp delete mode 100644 modules/optim/test/test_main.cpp delete mode 100644 modules/optim/test/test_precomp.cpp delete mode 100644 modules/optim/test/test_precomp.hpp diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index b5de99de0d..a73df3230f 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,2 +1,3 @@ set(the_description "Generic optimization") -ocv_define_module(optim) +ocv_define_module(optim opencv_imgproc) +#ocv_define_module(optim core) diff --git a/modules/optim/doc/denoising.rst b/modules/optim/doc/denoising.rst deleted file mode 100644 index 97625d3b31..0000000000 --- a/modules/optim/doc/denoising.rst +++ /dev/null @@ -1,91 +0,0 @@ -Denoising -========== - -.. highlight:: cpp - -fastNlMeansDenoising --------------------- -Perform image denoising using Non-local Means Denoising algorithm http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ -with several computational optimizations. Noise expected to be a gaussian white noise - -.. ocv:function:: void fastNlMeansDenoising( InputArray src, OutputArray dst, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param src: Input 8-bit 1-channel, 2-channel or 3-channel image. - - :param dst: Output image with the same size and type as ``src`` . - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength. Big h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - -This function expected to be applied to grayscale images. For colored images look at ``fastNlMeansDenoisingColored``. -Advanced usage of this functions can be manual denoising of colored image in different colorspaces. -Such approach is used in ``fastNlMeansDenoisingColored`` by converting image to CIELAB colorspace and then separately denoise L and AB components with different h parameter. - -fastNlMeansDenoisingColored ---------------------------- -Modification of ``fastNlMeansDenoising`` function for colored images - -.. ocv:function:: void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param src: Input 8-bit 3-channel image. - - :param dst: Output image with the same size and type as ``src`` . - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - - :param hForColorComponents: The same as h but for color components. For most images value equals 10 will be enought to remove colored noise and do not distort colors - -The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoising`` function. - -fastNlMeansDenoisingMulti -------------------------- -Modification of ``fastNlMeansDenoising`` function for images sequence where consequtive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. -For more details see http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.6394 - -.. ocv:function:: void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param srcImgs: Input 8-bit 1-channel, 2-channel or 3-channel images sequence. All images should have the same type and size. - - :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence - - :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. - - :param dst: Output image with the same size and type as ``srcImgs`` images. - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise - -fastNlMeansDenoisingColoredMulti --------------------------------- -Modification of ``fastNlMeansDenoisingMulti`` function for colored images sequences - -.. ocv:function:: void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h=3, float hColor=3, int templateWindowSize=7, int searchWindowSize=21 ) - - :param srcImgs: Input 8-bit 3-channel images sequence. All images should have the same type and size. - - :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence - - :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. - - :param dst: Output image with the same size and type as ``srcImgs`` images. - - :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels - - :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels - - :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise. - - :param hForColorComponents: The same as h but for color components. - -The function converts images to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoisingMulti`` function. - diff --git a/modules/optim/doc/inpainting.rst b/modules/optim/doc/inpainting.rst deleted file mode 100644 index 9b66266136..0000000000 --- a/modules/optim/doc/inpainting.rst +++ /dev/null @@ -1,32 +0,0 @@ -Inpainting -========== - -.. highlight:: cpp - -inpaint ------------ -Restores the selected region in an image using the region neighborhood. - -.. ocv:function:: void inpaint( InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags ) - -.. ocv:pyfunction:: cv2.inpaint(src, inpaintMask, inpaintRadius, flags[, dst]) -> dst - -.. ocv:cfunction:: void cvInpaint( const CvArr* src, const CvArr* inpaint_mask, CvArr* dst, double inpaintRange, int flags ) - - :param src: Input 8-bit 1-channel or 3-channel image. - - :param inpaintMask: Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted. - - :param dst: Output image with the same size and type as ``src`` . - - :param inpaintRadius: Radius of a circular neighborhood of each point inpainted that is considered by the algorithm. - - :param flags: Inpainting method that could be one of the following: - - * **INPAINT_NS** Navier-Stokes based method. - - * **INPAINT_TELEA** Method by Alexandru Telea [Telea04]_. - -The function reconstructs the selected image area from the pixel near the area boundary. The function may be used to remove dust and scratches from a scanned photo, or to remove undesirable objects from still images or video. See -http://en.wikipedia.org/wiki/Inpainting -for more details. diff --git a/modules/optim/doc/photo.rst b/modules/optim/doc/photo.rst deleted file mode 100644 index fa2aa1ecb8..0000000000 --- a/modules/optim/doc/photo.rst +++ /dev/null @@ -1,11 +0,0 @@ -******************************** -photo. Computational Photography -******************************** - -.. highlight:: cpp - -.. toctree:: - :maxdepth: 2 - - inpainting - denoising diff --git a/modules/optim/include/opencv2/photo.hpp b/modules/optim/include/opencv2/optim.hpp similarity index 59% rename from modules/optim/include/opencv2/photo.hpp rename to modules/optim/include/opencv2/optim.hpp index 185b8dcc90..44b01efc57 100644 --- a/modules/optim/include/opencv2/photo.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -40,11 +40,11 @@ // //M*/ -#ifndef __OPENCV_PHOTO_HPP__ -#define __OPENCV_PHOTO_HPP__ +#ifndef __OPENCV_OPTIM_HPP__ +#define __OPENCV_OPTIM_HPP__ #include "opencv2/core.hpp" -#include "opencv2/imgproc.hpp" +#include "opencv2/core/mat.hpp" /*! \namespace cv Namespace where all the C++ OpenCV functionality resides @@ -52,34 +52,35 @@ namespace cv { -//! the inpainting algorithm -enum +/* //! restores the damaged image areas using one of the available intpainting algorithms */ +class Solver : public Algorithm /* Algorithm is the base OpenCV class */ { - INPAINT_NS = 0, // Navier-Stokes algorithm - INPAINT_TELEA = 1 // A. Telea algorithm + class Function + { + public: + virtual ~Function(); + virtual double calc(InputArray args) const = 0; + //virtual double calc(InputArray args, OutputArray grad) const = 0; + }; + + // could be reused for all the generic algorithms like downhill simplex. + virtual void solve(InputArray x0, OutputArray result) const = 0; + + virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0; + + // more detailed API to be defined later ... + }; -//! restores the damaged image areas using one of the available intpainting algorithms -CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, - OutputArray dst, double inpaintRadius, int flags ); +class LPSolver : public Solver +{ +public: + virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; + // ... +}; - -CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); - -CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); - -} // cv +Ptr createLPSimplexSolver(); +}// cv #endif diff --git a/modules/optim/include/opencv2/photo/photo.hpp b/modules/optim/include/opencv2/optim/optim.hpp similarity index 98% rename from modules/optim/include/opencv2/photo/photo.hpp rename to modules/optim/include/opencv2/optim/optim.hpp index 41aa7ae405..b5a9ebf794 100644 --- a/modules/optim/include/opencv2/photo/photo.hpp +++ b/modules/optim/include/opencv2/optim/optim.hpp @@ -45,4 +45,4 @@ #error this is a compatibility header which should not be used inside the OpenCV library #endif -#include "opencv2/photo.hpp" \ No newline at end of file +#include "opencv2/optim.hpp" diff --git a/modules/optim/perf/perf_inpaint.cpp b/modules/optim/perf/perf_inpaint.cpp deleted file mode 100644 index 2debcf5c5e..0000000000 --- a/modules/optim/perf/perf_inpaint.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "perf_precomp.hpp" - -using namespace std; -using namespace cv; -using namespace perf; -using std::tr1::make_tuple; -using std::tr1::get; - -CV_ENUM(InpaintingMethod, INPAINT_NS, INPAINT_TELEA) -typedef std::tr1::tuple InpaintArea_InpaintingMethod_t; -typedef perf::TestBaseWithParam InpaintArea_InpaintingMethod; - - -PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint, - testing::Combine( - testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64), - InpaintingMethod::all() - ) - ) -{ - Mat src = imread(getDataPath("gpu/hog/road.png")); - - Size sz = get<0>(GetParam()); - int inpaintingMethod = get<1>(GetParam()); - - Mat mask(src.size(), CV_8UC1, Scalar(0)); - Mat result(src.size(), src.type()); - - Rect inpaintArea(src.cols/3, src.rows/3, sz.width, sz.height); - mask(inpaintArea).setTo(255); - - declare.in(src, mask).out(result).time(120); - - TEST_CYCLE() inpaint(src, mask, result, 10.0, inpaintingMethod); - - Mat inpaintedArea = result(inpaintArea); - SANITY_CHECK(inpaintedArea); -} diff --git a/modules/optim/perf/perf_main.cpp b/modules/optim/perf/perf_main.cpp deleted file mode 100644 index f5863c1974..0000000000 --- a/modules/optim/perf/perf_main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "perf_precomp.hpp" - -CV_PERF_TEST_MAIN(photo) diff --git a/modules/optim/perf/perf_precomp.cpp b/modules/optim/perf/perf_precomp.cpp deleted file mode 100644 index 8552ac3d42..0000000000 --- a/modules/optim/perf/perf_precomp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "perf_precomp.hpp" diff --git a/modules/optim/perf/perf_precomp.hpp b/modules/optim/perf/perf_precomp.hpp deleted file mode 100644 index 1fd0c81093..0000000000 --- a/modules/optim/perf/perf_precomp.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#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_PERF_PRECOMP_HPP__ -#define __OPENCV_PERF_PRECOMP_HPP__ - -#include "opencv2/ts.hpp" -#include "opencv2/photo.hpp" -#include "opencv2/highgui.hpp" - -#ifdef GTEST_CREATE_SHARED_LIBRARY -#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined -#endif - -#endif diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 7fb62e01fc..5559a0660b 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,45 +1,2 @@ -#include "opencv2/opencv.hpp" - -namespace cv { - namespace optim { - -class Solver : public Algorithm /* Algorithm is base OpenCV class */ -{ - class Function - { - public: - virtual ~Function() {} - virtual double calc(InputArray args) const = 0; - virtual double calc(InputArgs, OutputArray grad) const = 0; - }; - - // could be reused for all the generic algorithms like downhill simplex. - virtual void solve(InputArray x0, OutputArray result) const = 0; - - virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0; - - // more detailed API to be defined later ... -}; - -class LPSolver : public Solver -{ -public: - virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; - // ... -}; - -Ptr createLPSimplexSolver(); - -}} - -/*=============== -Hill climbing solver is more generic one:*/ -/* -class DownhillSolver : public Solver -{ -public: - // various setters and getters, if needed -}; - -Ptr createDownhillSolver(const Ptr& func);*/ +#include "precomp.hpp" +#include "opencv2/optim.hpp" diff --git a/modules/optim/src/precomp.cpp b/modules/optim/src/precomp.cpp new file mode 100644 index 0000000000..3e0ec42de9 --- /dev/null +++ b/modules/optim/src/precomp.cpp @@ -0,0 +1,44 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/* End of file. */ diff --git a/modules/optim/include/opencv2/photo/photo_c.h b/modules/optim/src/precomp.hpp similarity index 77% rename from modules/optim/include/opencv2/photo/photo_c.h rename to modules/optim/src/precomp.hpp index 4ca05f2538..7aab572f88 100644 --- a/modules/optim/include/opencv2/photo/photo_c.h +++ b/modules/optim/src/precomp.hpp @@ -7,11 +7,11 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2008-2012, Willow Garage Inc., 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, @@ -40,30 +40,9 @@ // //M*/ -#ifndef __OPENCV_PHOTO_C_H__ -#define __OPENCV_PHOTO_C_H__ +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ -#include "opencv2/core/core_c.h" +#include "opencv2/optim.hpp" -#ifdef __cplusplus -extern "C" { #endif - -/* Inpainting algorithms */ -enum -{ - CV_INPAINT_NS =0, - CV_INPAINT_TELEA =1 -}; - - -/* Inpaints the selected region in the image */ -CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask, - CvArr* dst, double inpaintRange, int flags ); - - -#ifdef __cplusplus -} //extern "C" -#endif - -#endif //__OPENCV_PHOTO_C_H__ diff --git a/modules/optim/test/test_denoising.cpp b/modules/optim/test/test_denoising.cpp deleted file mode 100644 index ca4f63f222..0000000000 --- a/modules/optim/test/test_denoising.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using 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 "test_precomp.hpp" -#include "opencv2/photo.hpp" -#include - -using namespace cv; -using namespace std; - -//#define DUMP_RESULTS - -#ifdef DUMP_RESULTS -# define DUMP(image, path) imwrite(path, image) -#else -# define DUMP(image, path) -#endif - - -TEST(Photo_DenoisingGrayscale, regression) -{ - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - string original_path = folder + "lena_noised_gaussian_sigma=10.png"; - string expected_path = folder + "lena_noised_denoised_grayscale_tw=7_sw=21_h=10.png"; - - Mat original = imread(original_path, IMREAD_GRAYSCALE); - Mat expected = imread(expected_path, IMREAD_GRAYSCALE); - - ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - Mat result; - fastNlMeansDenoising(original, result, 10); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingColored, regression) -{ - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - string original_path = folder + "lena_noised_gaussian_sigma=10.png"; - string expected_path = folder + "lena_noised_denoised_lab12_tw=7_sw=21_h=10_h2=10.png"; - - Mat original = imread(original_path, IMREAD_COLOR); - Mat expected = imread(expected_path, IMREAD_COLOR); - - ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - Mat result; - fastNlMeansDenoisingColored(original, result, 10, 10); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingGrayscaleMulti, regression) -{ - const int imgs_count = 3; - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - - string expected_path = folder + "lena_noised_denoised_multi_tw=7_sw=21_h=15.png"; - Mat expected = imread(expected_path, IMREAD_GRAYSCALE); - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - vector original(imgs_count); - for (int i = 0; i < imgs_count; i++) - { - string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); - original[i] = imread(original_path, IMREAD_GRAYSCALE); - ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; - } - - Mat result; - fastNlMeansDenoisingMulti(original, result, imgs_count / 2, imgs_count, 15); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_DenoisingColoredMulti, regression) -{ - const int imgs_count = 3; - string folder = string(cvtest::TS::ptr()->get_data_path()) + "denoising/"; - - string expected_path = folder + "lena_noised_denoised_multi_lab12_tw=7_sw=21_h=10_h2=15.png"; - Mat expected = imread(expected_path, IMREAD_COLOR); - ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; - - vector original(imgs_count); - for (int i = 0; i < imgs_count; i++) - { - string original_path = format("%slena_noised_gaussian_sigma=20_multi_%d.png", folder.c_str(), i); - original[i] = imread(original_path, IMREAD_COLOR); - ASSERT_FALSE(original[i].empty()) << "Could not load input image " << original_path; - } - - Mat result; - fastNlMeansDenoisingColoredMulti(original, result, imgs_count / 2, imgs_count, 10, 15); - - DUMP(result, expected_path + ".res.png"); - - ASSERT_EQ(0, norm(result != expected)); -} - -TEST(Photo_White, issue_2646) -{ - cv::Mat img(50, 50, CV_8UC1, cv::Scalar::all(255)); - cv::Mat filtered; - cv::fastNlMeansDenoising(img, filtered); - - int nonWhitePixelsCount = (int)img.total() - cv::countNonZero(filtered == img); - - ASSERT_EQ(0, nonWhitePixelsCount); -} diff --git a/modules/optim/test/test_inpaint.cpp b/modules/optim/test/test_inpaint.cpp deleted file mode 100644 index 3c341b27a0..0000000000 --- a/modules/optim/test/test_inpaint.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using 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 "test_precomp.hpp" -#include - -using namespace std; -using namespace cv; - -class CV_InpaintTest : public cvtest::BaseTest -{ -public: - CV_InpaintTest(); - ~CV_InpaintTest(); -protected: - void run(int); -}; - -CV_InpaintTest::CV_InpaintTest() -{ -} -CV_InpaintTest::~CV_InpaintTest() {} - -void CV_InpaintTest::run( int ) -{ - string folder = string(ts->get_data_path()) + "inpaint/"; - Mat orig = imread(folder + "orig.png"); - Mat exp1 = imread(folder + "exp1.png"); - Mat exp2 = imread(folder + "exp2.png"); - Mat mask = imread(folder + "mask.png"); - - if (orig.empty() || exp1.empty() || exp2.empty() || mask.empty()) - { - ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); - return; - } - - Mat inv_mask; - mask.convertTo(inv_mask, CV_8UC3, -1.0, 255.0); - - Mat mask1ch; - cv::cvtColor(mask, mask1ch, COLOR_BGR2GRAY); - - Mat test = orig.clone(); - test.setTo(Scalar::all(255), mask1ch); - - Mat res1, res2; - inpaint( test, mask1ch, res1, 5, INPAINT_NS ); - inpaint( test, mask1ch, res2, 5, INPAINT_TELEA ); - - Mat diff1, diff2; - absdiff( orig, res1, diff1 ); - absdiff( orig, res2, diff2 ); - - double n1 = norm(diff1.reshape(1), NORM_INF, inv_mask.reshape(1)); - double n2 = norm(diff2.reshape(1), NORM_INF, inv_mask.reshape(1)); - - if (n1 != 0 || n2 != 0) - { - ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); - return; - } - - absdiff( exp1, res1, diff1 ); - absdiff( exp2, res2, diff2 ); - - n1 = norm(diff1.reshape(1), NORM_INF, mask.reshape(1)); - n2 = norm(diff2.reshape(1), NORM_INF, mask.reshape(1)); - - const int jpeg_thres = 3; - if (n1 > jpeg_thres || n2 > jpeg_thres) - { - ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); - return; - } - - ts->set_failed_test_info(cvtest::TS::OK); -} - -TEST(Photo_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); } diff --git a/modules/optim/test/test_main.cpp b/modules/optim/test/test_main.cpp deleted file mode 100644 index 6b24993447..0000000000 --- a/modules/optim/test/test_main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "test_precomp.hpp" - -CV_TEST_MAIN("cv") diff --git a/modules/optim/test/test_precomp.cpp b/modules/optim/test/test_precomp.cpp deleted file mode 100644 index 5956e13e3e..0000000000 --- a/modules/optim/test/test_precomp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "test_precomp.hpp" diff --git a/modules/optim/test/test_precomp.hpp b/modules/optim/test/test_precomp.hpp deleted file mode 100644 index 5b22a1c755..0000000000 --- a/modules/optim/test/test_precomp.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#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/photo.hpp" -#include "opencv2/highgui.hpp" - -#endif From b216c0940cdaac548395bcd401098b146e8d2dd3 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Mon, 24 Jun 2013 20:27:11 +0300 Subject: [PATCH 04/22] Created skeleton for simplex method. Added LPSolver class together with two nested classes: LPFunction and LPConstraints. These represent function to be maximized and constraints imposed respectively. They are implementations of interfaces Function and Constraints respectively (latter ones are nested classes of Solver interface, which is generic interface for all optimization algorithms to be implemented within this project). The next step is to implement the simplex algorithm! First, we shall implement it for the case of constraints of the form Ax<=b and x>=0. Then, we shall extend the sets of problems that can be handled by the conversion to the one we've handled already. Finally, we shale concentrate on numerical stability and efficiency. --- .gitignore | 1 + modules/optim/CMakeLists.txt | 3 +- modules/optim/include/opencv2/optim.hpp | 63 ++++++++++++++++++------- modules/optim/src/lpsolver.cpp | 22 ++++++++- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 0a19f3ceeb..caaebed0e3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ OpenCV4Tegra/ .sw[a-z] .*.swp tags +build/ diff --git a/modules/optim/CMakeLists.txt b/modules/optim/CMakeLists.txt index a73df3230f..c36c24d9de 100644 --- a/modules/optim/CMakeLists.txt +++ b/modules/optim/CMakeLists.txt @@ -1,3 +1,2 @@ set(the_description "Generic optimization") -ocv_define_module(optim opencv_imgproc) -#ocv_define_module(optim core) +ocv_define_module(optim opencv_core) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 44b01efc57..8464cf872d 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -43,44 +43,71 @@ #ifndef __OPENCV_OPTIM_HPP__ #define __OPENCV_OPTIM_HPP__ +#include #include "opencv2/core.hpp" #include "opencv2/core/mat.hpp" /*! \namespace cv Namespace where all the C++ OpenCV functionality resides */ -namespace cv +namespace cv{namespace optim { - -/* //! restores the damaged image areas using one of the available intpainting algorithms */ -class Solver : public Algorithm /* Algorithm is the base OpenCV class */ +//! generic class for optimization algorithms */ +class CV_EXPORTS Solver : public Algorithm /* Algorithm is the base OpenCV class */ { - class Function + public: + class CV_EXPORTS Function { public: - virtual ~Function(); + virtual ~Function(){} virtual double calc(InputArray args) const = 0; - //virtual double calc(InputArray args, OutputArray grad) const = 0; + }; + class CV_EXPORTS Constraints + { + public: + virtual ~Constraints(){} }; - // could be reused for all the generic algorithms like downhill simplex. - virtual void solve(InputArray x0, OutputArray result) const = 0; + //! could be reused for all the generic algorithms like downhill simplex. Return value is the maximum value of a function*/ + virtual double solve(const Function& F,const Constraints& C, OutputArray result) const = 0; - virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0; + /*virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0;*/ // more detailed API to be defined later ... - }; -class LPSolver : public Solver +class CV_EXPORTS LPSolver : public Solver { public: - virtual void solve(InputArray coeffs, InputArray constraints, OutputArray result) const = 0; - // ... -}; + class CV_EXPORTS LPFunction:public Solver::Function + { + cv::Mat z; + public: + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ + LPFunction(cv::Mat z_in):z(z_in){} + ~LPFunction(){}; + const cv::Mat& getz()const{return z;} + double calc(InputArray args)const; + }; -Ptr createLPSimplexSolver(); -}// cv + //!This class represents constraints for linear problem. There are two matrix stored: m-by-n matrix A and n-by-1 column-vector b. + //!What this represents is the set of constraints Ax\leq b and x\geq 0. It can be shown that any set of linear constraints can be converted + //!this form and **we shall create various constructors for this class that will perform these conversions**. + class CV_EXPORTS LPConstraints:public Solver::Constraints + { + cv::Mat A,b; + public: + ~LPConstraints(){}; + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ + LPConstraints(cv::Mat A_in, cv::Mat b_in):A(A_in),b(b_in){} + const cv::Mat& getA()const{return A;} + const cv::Mat& getb()const{return b;} + }; + + LPSolver(){} + double solve(const Function& F,const Constraints& C, OutputArray result)const; +}; +}}// cv #endif diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 5559a0660b..56dec12359 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,2 +1,22 @@ #include "precomp.hpp" -#include "opencv2/optim.hpp" + +namespace cv{namespace optim{ + +double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ + printf("call to solve\n"); + + //TODO: sanity check and throw exception, if appropriate + + //TODO: copy A,b,z + + //TODO: run simplex algo + + return 0.0; +} + +double LPSolver::LPFunction::calc(InputArray args)const{ + printf("call to LPFunction::calc()\n"); + return 0.0; +} + +}} From ddc0010e7da6daa4d8b6a543e853ef0b0ff4ff33 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Fri, 28 Jun 2013 15:28:57 +0300 Subject: [PATCH 05/22] The first draft of simplex algorithm, simple tests. What we have now corresponds to "formal simplex algorithm", described in Cormen's "Intro to Algorithms". It will work *only* if the initial problem has (0,0,0,...,0) as feasible solution (consequently, it will work unpredictably if problem was unfeasible or did not have zero-vector as feasible solution). Moreover, it might cycle. TODO (first priority) 1. Implement initialize_simplex() procedure, that shall check for feasibility and generate initial feasible solution. (in particular, code should pass all 4 tests implemented at the moment) 2. Implement Bland's rule to avoid cycling. 3. Make the code more clear. 4. Implement several non-trivial tests (??) and check algorithm against them. Debug if necessary. TODO (second priority) 1. Concentrate on stability and speed (make difficult tests) --- modules/optim/include/opencv2/optim.hpp | 15 +- modules/optim/src/lpsolver.cpp | 257 +++++++++++++++++++++++- modules/optim/test/test_lpsolver.cpp | 61 ++++++ modules/optim/test/test_main.cpp | 3 + modules/optim/test/test_precomp.cpp | 1 + modules/optim/test/test_precomp.hpp | 15 ++ 6 files changed, 338 insertions(+), 14 deletions(-) create mode 100644 modules/optim/test/test_lpsolver.cpp create mode 100644 modules/optim/test/test_main.cpp create mode 100644 modules/optim/test/test_precomp.cpp create mode 100644 modules/optim/test/test_precomp.hpp diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 8464cf872d..f4a639f8bb 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -82,12 +82,12 @@ class CV_EXPORTS LPSolver : public Solver public: class CV_EXPORTS LPFunction:public Solver::Function { - cv::Mat z; + Mat z; public: //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ - LPFunction(cv::Mat z_in):z(z_in){} + LPFunction(Mat z_in):z(z_in){} ~LPFunction(){}; - const cv::Mat& getz()const{return z;} + const Mat& getz()const{return z;} double calc(InputArray args)const; }; @@ -96,18 +96,19 @@ public: //!this form and **we shall create various constructors for this class that will perform these conversions**. class CV_EXPORTS LPConstraints:public Solver::Constraints { - cv::Mat A,b; + Mat A,b; public: ~LPConstraints(){}; //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ - LPConstraints(cv::Mat A_in, cv::Mat b_in):A(A_in),b(b_in){} - const cv::Mat& getA()const{return A;} - const cv::Mat& getb()const{return b;} + LPConstraints(Mat A_in, Mat b_in):A(A_in),b(b_in){} + const Mat& getA()const{return A;} + const Mat& getb()const{return b;} }; LPSolver(){} double solve(const Function& F,const Constraints& C, OutputArray result)const; }; +CV_EXPORTS_W int solveLP(const Mat& Func, const Mat& Constr, Mat& z); }}// cv #endif diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 56dec12359..b9cabc1180 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,15 +1,12 @@ +#include "opencv2/ts.hpp" #include "precomp.hpp" +#include +#include namespace cv{namespace optim{ +using std::vector; double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ - printf("call to solve\n"); - - //TODO: sanity check and throw exception, if appropriate - - //TODO: copy A,b,z - - //TODO: run simplex algo return 0.0; } @@ -18,5 +15,251 @@ double LPSolver::LPFunction::calc(InputArray args)const{ printf("call to LPFunction::calc()\n"); return 0.0; } +void print_matrix(const Mat& X){ + printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); + for(int i=0;i(i,j)); + } + printf("]\n"); + } +} +namespace solveLP_aux{ + //return -1 if problem is unfeasible, 0 if feasible + //in latter case it returns feasible solution in z with homogenised b's and v + int initialize_simplex(const Mat& c, Mat& b, Mat& z,double& v); +} +int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ + printf("call to solveLP\n");//-3(incorrect),-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) + + //sanity check (size, type, no. of channels) (and throw exception, if appropriate) + if(Func.type()!=CV_64FC1 || Constr.type()!=CV_64FC1){ + printf("both Func and Constr should be one-channel matrices of double's\n"); + return -3; + } + if(Func.rows!=1){ + printf("Func should be row-vector\n"); + return -3; + } + vector N(Func.cols); + N[0]=1; + for (std::vector::iterator it = N.begin()+1 ; it != N.end(); ++it){ + *it=it[-1]+1; + } + if((Constr.cols-1)!=Func.cols){ + printf("Constr should have one more column when compared to Func\n"); + return -3; + } + vector B(Constr.rows); + B[0]=Func.cols+1; + for (std::vector::iterator it = B.begin()+1 ; it != B.end(); ++it){ + *it=it[-1]+1; + } + + //copy arguments for we will shall modify them + Mat c=Func.clone(), + b=Constr.clone(); + double v=0; + + solveLP_aux::initialize_simplex(c,b,z,v); + + int count=0; + while(1){ + printf("iteration #%d\n",count++); + + MatIterator_ pos_ptr; + int e=0; + for(pos_ptr=c.begin();(*pos_ptr<=0) && pos_ptr!=c.end();pos_ptr++,e++); + if(pos_ptr==c.end()){ + break; + } + printf("offset of first nonneg coef is %d\n",e);//TODO: choose the var with the smallest index + + int l=-1; + double min=DBL_MAX; + int row_it=0; + double ite=0; + MatIterator_ min_row_ptr=b.begin(); + for(MatIterator_ it=b.begin();it!=b.end();it+=b.cols,row_it++){ + double myite=0; + //check constraints, select the tightest one, TODO: smallest index + if((myite=it[e])>0){ + double val=it[b.cols-1]/myite; + if(val it=min_row_ptr;col_count it=b.begin();row_count()); + if(row_count==l){ + it+=b.cols; + }else{ + //remaining constraints + double coef=it[e]; + MatIterator_ shadow_it=min_row_ptr; + for(int col_it=0;col_it<(b.cols);col_it++,it++,shadow_it++){ + if(col_it==e){ + *it=-coef*(*shadow_it); + }else{ + *it-=coef*(*shadow_it); + } + } + } + } + //objective function + double coef=*pos_ptr; + MatIterator_ shadow_it=min_row_ptr; + MatIterator_ it=c.begin(); + for(int col_it=0;col_it<(b.cols-1);col_it++,it++,shadow_it++){ + if(col_it==e){ + *it=-coef*(*shadow_it); + }else{ + *it-=coef*(*shadow_it); + } + } + v+=coef*(*shadow_it); + + //new basis and nonbasic sets + int tmp=N[e]; + N[e]=B[l]; + B[l]=tmp; + + printf("objective, v=%g\n",v); + print_matrix(c); + printf("constraints\n"); + print_matrix(b); + printf("non-basic: "); + for (std::vector::iterator it = N.begin() ; it != N.end(); ++it){ + printf("%d, ",*it); + } + printf("\nbasic: "); + for (std::vector::iterator it = B.begin() ; it != B.end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); + } + + //return the optimal solution + //z=cv::Mat_(1,c.cols,0); + MatIterator_ it=z.begin(); + for(int i=1;i<=c.cols;i++,it++){ + std::vector::iterator pos=B.begin(); + if((pos=std::find(B.begin(),B.end(),i))==B.end()){ + *it+=0; + }else{ + *it+=b.at(pos-B.begin(),b.cols-1); + } + } + + return 0; +} +int solveLP_aux::initialize_simplex(const Mat& c, Mat& b, Mat& z,double& v){//TODO + z=Mat_(1,c.cols,0.0); + v=0; + return 0; + + cv::Mat mod_b=(cv::Mat_(1,b.rows)); + bool gen_new_sol_flag=false,hom_sol_given=false; + if(z.type()!=CV_64FC1 || z.rows!=1 || z.cols!=c.cols || (hom_sol_given=(countNonZero(z)==0))){ + printf("line %d\n",__LINE__); + if(hom_sol_given==false){ + printf("line %d, %d\n",__LINE__,hom_sol_given); + z=cv::Mat_(1,c.cols,(double)0); + } + //check homogeneous solution + printf("line %d\n",__LINE__); + for(MatIterator_ b_it=b.begin()+b.cols-1,mod_b_it=mod_b.begin();mod_b_it!=mod_b.end(); + b_it+=b.cols,mod_b_it++){ + if(*b_it<0){ + //if no - we need feasible solution + gen_new_sol_flag=true; + break; + } + } + printf("line %d, gen_new_sol_flag=%d - I've got here!!!\n",__LINE__,gen_new_sol_flag); + //if yes - we have feasible solution! + }else{ + //check for feasibility + MatIterator_ it=b.begin(); + for(MatIterator_ mod_b_it=mod_b.begin();it!=b.end();mod_b_it++){ + double sum=0; + for(MatIterator_ z_it=z.begin();z_it!=z.end();z_it++,it++){ + sum+=(*it)*(*z_it); + } + if((*mod_b_it=(*it-sum))<0){ + break; + } + it++; + } + if(it==b.end()){ + //z contains feasible solution - just homogenise b's TODO: and v + gen_new_sol_flag=false; + for(MatIterator_ b_it=b.begin()+b.cols-1,mod_b_it=mod_b.begin();mod_b_it!=mod_b.end(); + b_it+=b.cols,mod_b_it++){ + *b_it=*mod_b_it; + } + }else{ + //if no - we need feasible solution + gen_new_sol_flag=true; + } + } + if(gen_new_sol_flag==true){ + //we should generate new solution - TODO + printf("we should generate new solution\n"); + Mat new_c=Mat_(1,c.cols+1,0.0), + new_b=Mat_(b.rows,b.cols+1,-1.0), + new_z=Mat_(1,c.cols+1,0.0); + + new_c.end()[-1]=-1; + c.copyTo(new_c.colRange(0,new_c.cols-1)); + + b.col(b.cols-1).copyTo(new_b.col(new_b.cols-1)); + b.colRange(0,b.cols-1).copyTo(new_b.colRange(0,new_b.cols-2)); + + Mat b_slice=b.col(b.cols-1); + new_z.end()[-1]=-*(std::min_element(b_slice.begin(),b_slice.end())); + + /*printf("matrix new_c\n"); + print_matrix(new_c); + printf("matrix new_b\n"); + print_matrix(new_b); + printf("matrix new_z\n"); + print_matrix(new_z);*/ + + printf("run for the second time!\n"); + solveLP(new_c,new_b,new_z); + printf("original z was\n"); + print_matrix(z); + printf("that's what I've got\n"); + print_matrix(new_z); + printf("for the constraints\n"); + print_matrix(b); + return 0; + } + +} }} diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp new file mode 100644 index 0000000000..c95edf5099 --- /dev/null +++ b/modules/optim/test/test_lpsolver.cpp @@ -0,0 +1,61 @@ +#include "test_precomp.hpp" +#include "opencv2/optim.hpp" + +TEST(Optim_LpSolver, regression) +{ + cv::Mat A,B,z,etalon_z; + + if(true){ + //cormen's example #1 + A=(cv::Mat_(1,3)<<3,1,2); + B=(cv::Mat_(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36); + std::cout<<"here A goes\n"<(1,3)<<8,4,0); + ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); + } + + if(true){ + //cormen's example #2 + A=(cv::Mat_(1,2)<<18,12.5); + B=(cv::Mat_(3,3)<<1,1,20,1,0,20,0,1,16); + std::cout<<"here A goes\n"<(1,2)<<20,0); + ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); + } + + if(true){ + //cormen's example #3 + A=(cv::Mat_(1,2)<<5,-3); + B=(cv::Mat_(2,3)<<1,-1,1,2,1,2); + std::cout<<"here A goes\n"<(1,2)<<1,0); + ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); + + } + if(false){ + //cormen's example #4 - unfeasible + A=(cv::Mat_(1,3)<<-1,-1,-1); + B=(cv::Mat_(2,4)<<-2,-7.5,-3,-10000,-20,-5,-10,-30000); + std::cout<<"here A goes\n"<(1,2)<<1,0); + ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); + } +} + +//TODO +// get optimal solution from initial (0,0,...,0) - DONE +// milestone: pass first test (wo initial solution) - DONE + // learn how to get initial solution + // Blands_rule + // 1_more_test & make_more_clear + // -> **contact_Vadim**: min_l2_norm, init_optional_fsbl_check, error_codes, comment_style-too_many?, copyTo temp headers +// ??how to get smallest l2 norm +// FUTURE: compress&debug-> more_tests(Cormen) -> readNumRecipes-> fast&stable || hill_climbing diff --git a/modules/optim/test/test_main.cpp b/modules/optim/test/test_main.cpp new file mode 100644 index 0000000000..6b24993447 --- /dev/null +++ b/modules/optim/test/test_main.cpp @@ -0,0 +1,3 @@ +#include "test_precomp.hpp" + +CV_TEST_MAIN("cv") diff --git a/modules/optim/test/test_precomp.cpp b/modules/optim/test/test_precomp.cpp new file mode 100644 index 0000000000..5956e13e3e --- /dev/null +++ b/modules/optim/test/test_precomp.cpp @@ -0,0 +1 @@ +#include "test_precomp.hpp" diff --git a/modules/optim/test/test_precomp.hpp b/modules/optim/test/test_precomp.hpp new file mode 100644 index 0000000000..9a86cab4b5 --- /dev/null +++ b/modules/optim/test/test_precomp.hpp @@ -0,0 +1,15 @@ +#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 "opencv2/ts.hpp" +#include "opencv2/optim.hpp" + +#endif From a4a5e98cc06a9217d0ac6950ab0f11d465d04f2a Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Wed, 3 Jul 2013 13:54:23 +0300 Subject: [PATCH 06/22] Non-optimized simplex algorithm. This version is supposed to work on all problems (please, let me know if this is not so), but is not optimized yet in terms of numerical stability and performance. Bland's rule is implemented as well, so algorithm is supposed to allow no cycling. Additional check for multiple solutions is added (in case of multiple solutions algorithm returns an appropriate return code of 1 and returns arbitrary optimal solution). Finally, now we have 5 tests. Before Thursday we have 4 directions that can be tackled in parallel: *) Prepare the pull request! *) Make the code more clear and readable (refactoring) *) Wrap the core solveLP() procedure in OOP-style interface *) Test solveLP on non-trivial tests (possibly test against http://www.coin-or.org/Clp/) --- modules/optim/src/lpsolver.cpp | 411 ++++++++++++++++----------- modules/optim/test/test_lpsolver.cpp | 89 +++++- 2 files changed, 322 insertions(+), 178 deletions(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index b9cabc1180..b56dc3e3a6 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -25,68 +25,232 @@ void print_matrix(const Mat& X){ printf("]\n"); } } -namespace solveLP_aux{ - //return -1 if problem is unfeasible, 0 if feasible - //in latter case it returns feasible solution in z with homogenised b's and v - int initialize_simplex(const Mat& c, Mat& b, Mat& z,double& v); +void print_simplex_state(const Mat& c,const Mat&b,double v,const vector& N,const vector& B){ + printf("\tprint simplex state\n"); + + printf("v=%g\n",v); + + printf("here c goes\n"); + print_matrix(c); + + printf("non-basic: "); + for (std::vector::const_iterator it = N.begin() ; it != N.end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); + + printf("here b goes\n"); + print_matrix(b); + printf("basic: "); + + for (std::vector::const_iterator it = B.begin() ; it != B.end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); } + +namespace solveLP_aux{ + /**Due to technical considerations, the format of input b and c is somewhat special: + *both b and c should be one column bigger than corresponding b and c of linear problem and the leftmost column will be used internally + by this procedure - it should not be cleaned before the call to procedure and may contain mess after + it also initializes N and B and does not make any assumptions about their init values + * @return -1 if problem is unfeasible, 0 if feasible. + */ + int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); + inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); + /**@return -2 means the problem is unbdd, 1 means multiple solutions, 0 means successful. + */ + int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); + void swap_columns(Mat_& A,int col1,int col2); +} + +//return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ - printf("call to solveLP\n");//-3(incorrect),-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) + printf("call to solveLP\n"); //sanity check (size, type, no. of channels) (and throw exception, if appropriate) - if(Func.type()!=CV_64FC1 || Constr.type()!=CV_64FC1){ - printf("both Func and Constr should be one-channel matrices of double's\n"); - return -3; + CV_Assert(Func.type()==CV_64FC1); + CV_Assert(Constr.type()==CV_64FC1); + CV_Assert(Func.rows==1); + CV_Assert(Constr.cols-Func.cols==1); + + //copy arguments for we will shall modify them + Mat_ bigC=Mat_(1,Func.cols+1), + bigB=Mat_(Constr.rows,Constr.cols+1); + Func.copyTo(bigC.colRange(1,bigC.cols)); + Constr.copyTo(bigB.colRange(1,bigB.cols)); + double v=0; + vector N,B; + + if(solveLP_aux::initialize_simplex(bigC,bigB,v,N,B)==-1){ + return -1; } - if(Func.rows!=1){ - printf("Func should be row-vector\n"); - return -3; + Mat_ c=bigC.colRange(1,bigC.cols), + b=bigB.colRange(1,bigB.cols); + + int res=0; + if((res=solveLP_aux::inner_simplex(c,b,v,N,B))==-2){ + return -2; } - vector N(Func.cols); - N[0]=1; + + //return the optimal solution + const int z_size[]={1,c.cols}; + z.create(2,z_size,CV_64FC1); + MatIterator_ it=z.begin(); + for(int i=1;i<=c.cols;i++,it++){ + std::vector::iterator pos=B.begin(); + if((pos=std::find(B.begin(),B.end(),i))==B.end()){ + *it=0; + }else{ + *it=b.at(pos-B.begin(),b.cols-1); + } + } + + return res; +} + +int solveLP_aux::initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ + N.resize(c.cols); + N[0]=0; for (std::vector::iterator it = N.begin()+1 ; it != N.end(); ++it){ *it=it[-1]+1; } - if((Constr.cols-1)!=Func.cols){ - printf("Constr should have one more column when compared to Func\n"); - return -3; - } - vector B(Constr.rows); - B[0]=Func.cols+1; + B.resize(b.rows); + B[0]=N.size(); for (std::vector::iterator it = B.begin()+1 ; it != B.end(); ++it){ *it=it[-1]+1; } + v=0; - //copy arguments for we will shall modify them - Mat c=Func.clone(), - b=Constr.clone(); - double v=0; + int k=0; + { + double min=DBL_MAX; + for(int i=0;i=0){ + N.erase(N.begin()); + return 0; + } + Mat_ old_c=c.clone(); + c=0; + c(0,0)=-1; + for(int i=0;i::iterator it=std::find(B.begin(),B.end(),0); + if(it!=B.end()){ + int it_offset=it-B.begin(); + if(b(it_offset,b.cols-1)>0){ + return -1; + } + pivot(c,b,v,N,B,it_offset,0); + } + + it=std::find(N.begin(),N.end(),0); + int it_offset=it-N.begin(); + std::iter_swap(it,N.begin()); + swap_columns(c,it_offset,0); + swap_columns(b,it_offset,0); + + printf("after swaps\n"); + print_simplex_state(c,b,v,N,B); + + //start from 1, because we ignore x_0 + c=0; + v=0; + for(int i=1;i& c, Mat_& b,double& v,vector& N,vector& B){ int count=0; while(1){ printf("iteration #%d\n",count++); MatIterator_ pos_ptr; - int e=0; - for(pos_ptr=c.begin();(*pos_ptr<=0) && pos_ptr!=c.end();pos_ptr++,e++); - if(pos_ptr==c.end()){ - break; + int e=-1,pos_ctr=0,min_var=INT_MAX; + bool all_nonzero=true; + for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){ + if(*pos_ptr==0){ + all_nonzero=false; + } + if(*pos_ptr>0){ + if(N[pos_ctr] min_row_ptr=b.begin(); - for(MatIterator_ it=b.begin();it!=b.end();it+=b.cols,row_it++){ + MatIterator_ min_row_ptr=b.begin(); + for(MatIterator_ it=b.begin();it!=b.end();it+=b.cols,row_it++){ double myite=0; - //check constraints, select the tightest one, TODO: smallest index + //check constraints, select the tightest one, reinforcing Bland's rule if((myite=it[e])>0){ double val=it[b.cols-1]/myite; - if(val it=min_row_ptr;col_count it=b.begin();row_count()); - if(row_count==l){ - it+=b.cols; - }else{ - //remaining constraints - double coef=it[e]; - MatIterator_ shadow_it=min_row_ptr; - for(int col_it=0;col_it<(b.cols);col_it++,it++,shadow_it++){ - if(col_it==e){ - *it=-coef*(*shadow_it); - }else{ - *it-=coef*(*shadow_it); - } - } - } - } - //objective function - double coef=*pos_ptr; - MatIterator_ shadow_it=min_row_ptr; - MatIterator_ it=c.begin(); - for(int col_it=0;col_it<(b.cols-1);col_it++,it++,shadow_it++){ - if(col_it==e){ - *it=-coef*(*shadow_it); - }else{ - *it-=coef*(*shadow_it); - } - } - v+=coef*(*shadow_it); - - //new basis and nonbasic sets - int tmp=N[e]; - N[e]=B[l]; - B[l]=tmp; + solveLP_aux::pivot(c,b,v,N,B,l,e); printf("objective, v=%g\n",v); print_matrix(c); @@ -161,105 +280,57 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ } printf("\n"); } - - //return the optimal solution - //z=cv::Mat_(1,c.cols,0); - MatIterator_ it=z.begin(); - for(int i=1;i<=c.cols;i++,it++){ - std::vector::iterator pos=B.begin(); - if((pos=std::find(B.begin(),B.end(),i))==B.end()){ - *it+=0; - }else{ - *it+=b.at(pos-B.begin(),b.cols-1); - } - } - - return 0; } -int solveLP_aux::initialize_simplex(const Mat& c, Mat& b, Mat& z,double& v){//TODO - z=Mat_(1,c.cols,0.0); - v=0; - return 0; - cv::Mat mod_b=(cv::Mat_(1,b.rows)); - bool gen_new_sol_flag=false,hom_sol_given=false; - if(z.type()!=CV_64FC1 || z.rows!=1 || z.cols!=c.cols || (hom_sol_given=(countNonZero(z)==0))){ - printf("line %d\n",__LINE__); - if(hom_sol_given==false){ - printf("line %d, %d\n",__LINE__,hom_sol_given); - z=cv::Mat_(1,c.cols,(double)0); - } - //check homogeneous solution - printf("line %d\n",__LINE__); - for(MatIterator_ b_it=b.begin()+b.cols-1,mod_b_it=mod_b.begin();mod_b_it!=mod_b.end(); - b_it+=b.cols,mod_b_it++){ - if(*b_it<0){ - //if no - we need feasible solution - gen_new_sol_flag=true; - break; - } - } - printf("line %d, gen_new_sol_flag=%d - I've got here!!!\n",__LINE__,gen_new_sol_flag); - //if yes - we have feasible solution! - }else{ - //check for feasibility - MatIterator_ it=b.begin(); - for(MatIterator_ mod_b_it=mod_b.begin();it!=b.end();mod_b_it++){ - double sum=0; - for(MatIterator_ z_it=z.begin();z_it!=z.end();z_it++,it++){ - sum+=(*it)*(*z_it); - } - if((*mod_b_it=(*it-sum))<0){ - break; - } - it++; - } - if(it==b.end()){ - //z contains feasible solution - just homogenise b's TODO: and v - gen_new_sol_flag=false; - for(MatIterator_ b_it=b.begin()+b.cols-1,mod_b_it=mod_b.begin();mod_b_it!=mod_b.end(); - b_it+=b.cols,mod_b_it++){ - *b_it=*mod_b_it; - } +inline void solveLP_aux::pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ + double coef=b(leaving_index,entering_index); + for(int i=0;i(1,c.cols+1,0.0), - new_b=Mat_(b.rows,b.cols+1,-1.0), - new_z=Mat_(1,c.cols+1,0.0); - new_c.end()[-1]=-1; - c.copyTo(new_c.colRange(0,new_c.cols-1)); - - b.col(b.cols-1).copyTo(new_b.col(new_b.cols-1)); - b.colRange(0,b.cols-1).copyTo(new_b.colRange(0,new_b.cols-2)); - - Mat b_slice=b.col(b.cols-1); - new_z.end()[-1]=-*(std::min_element(b_slice.begin(),b_slice.end())); - - /*printf("matrix new_c\n"); - print_matrix(new_c); - printf("matrix new_b\n"); - print_matrix(new_b); - printf("matrix new_z\n"); - print_matrix(new_z);*/ - - printf("run for the second time!\n"); - solveLP(new_c,new_b,new_z); - printf("original z was\n"); - print_matrix(z); - printf("that's what I've got\n"); - print_matrix(new_z); - printf("for the constraints\n"); - print_matrix(b); - return 0; + for(int i=0;i& A,int col1,int col2){ + for(int i=0;i(1,2)<<1,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); - } - if(false){ +} + +TEST(Optim_LpSolver, regression_init_unfeasible){ + cv::Mat A,B,z,etalon_z; + + if(true){ //cormen's example #4 - unfeasible A=(cv::Mat_(1,3)<<-1,-1,-1); B=(cv::Mat_(2,4)<<-2,-7.5,-3,-10000,-20,-5,-10,-30000); std::cout<<"here A goes\n"<(1,2)<<1,0); + etalon_z=(cv::Mat_(1,3)<<1250,1000,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } } +TEST(Optim_LpSolver, regression_absolutely_unfeasible){ + cv::Mat A,B,z,etalon_z; + + if(true){ + //trivial absolutely unfeasible example + A=(cv::Mat_(1,1)<<1); + B=(cv::Mat_(2,2)<<1,-1); + std::cout<<"here A goes\n"<(1,2)<<1,1); + B=(cv::Mat_(1,3)<<1,1,1); + std::cout<<"here A goes\n"<(1,2)<<2,-1); + B=(cv::Mat_(2,3)<<2,-1,2,1,-5,-4); + std::cout<<"here A goes\n"<(1,4)<<10,-57,-9,-24); + B=(cv::Mat_(3,5)<<0.5,-5.5,-2.5,9,0,0.5,-1.5,-0.5,1,0,1,0,0,0,1); + std::cout<<"here A goes\n"< **contact_Vadim**: min_l2_norm, init_optional_fsbl_check, error_codes, comment_style-too_many?, copyTo temp headers + // + // ??how_check_multiple_solutions & pass_test - DONE + // Blands_rule - DONE + // (&1tests on cycling) + // + // make_more_clear (assert, assign) + // wrap in OOP + // + // non-trivial tests + // pull-request + // + // study hill and other algos + // // ??how to get smallest l2 norm // FUTURE: compress&debug-> more_tests(Cormen) -> readNumRecipes-> fast&stable || hill_climbing From a95650111f813d99f82f672b3caaee7f9fa3df04 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Wed, 10 Jul 2013 20:11:52 +0300 Subject: [PATCH 07/22] Cleaning the code of simplex method In particular, the following things are done: *) Consistent tabulation of 4 spaces is ensured *) New function dprintf() is introduced, so now printing of the debug information can be turned on/off via the ALEX_DEBUG macro *) Removed solveLP_aux namespace *) All auxiliary functions are declared as static *) The return codes of solveLP() are encapsulated in enum. --- modules/optim/doc/linear_programming.rst | 48 +++++++ modules/optim/doc/optim.rst | 10 ++ modules/optim/include/opencv2/optim.hpp | 94 +++++++------- modules/optim/src/lpsolver.cpp | 151 ++++++++++++----------- modules/optim/test/test_lpsolver.cpp | 8 +- 5 files changed, 193 insertions(+), 118 deletions(-) create mode 100644 modules/optim/doc/linear_programming.rst create mode 100644 modules/optim/doc/optim.rst diff --git a/modules/optim/doc/linear_programming.rst b/modules/optim/doc/linear_programming.rst new file mode 100644 index 0000000000..fbc1d04e33 --- /dev/null +++ b/modules/optim/doc/linear_programming.rst @@ -0,0 +1,48 @@ +Linear Programming +================== + +.. highlight:: cpp + +optim::solveLP +-------------------- +Solve given (non-integer) linear programming problem using the Simplex Algorithm (Simplex Method). +What we mean here by "linear programming problem" (or LP problem, for short) can be +formulated as: + +.. math:: + \mbox{Maximize } c\cdot x\\ + \mbox{Subject to:}\\ + Ax\leq b\\ + x\geq 0 + +Where :math:`c` is fixed *1*-by-*n* row-vector, :math:`A` is fixed *m*-by-*n* matrix, :math:`b` is fixed *m*-by-*1* column vector and +:math:`x` is an arbitrary *n*-by-*1* column vector, which satisfies the constraints. + +Simplex algorithm is one of many algorithms that are designed to handle this sort of problems efficiently. Although it is not optimal in theoretical +sense (there exist algorithms that can solve any problem written as above in polynomial type, while simplex method degenerates to exponential time +for some special cases), it is well-studied, easy to implement and is shown to work well for real-life purposes. + +The particular implementation is taken almost verbatim from **Introduction to Algorithms, third edition** +by T. H. Cormen, C. E. Leiserson, R. L. Rivest and Clifford Stein. In particular, the Bland's rule +(`http://en.wikipedia.org/wiki/Bland%27s\_rule `_) is used to prevent cycling. + +.. ocv:function:: int optim::solveLP(const Mat& Func, const Mat& Constr, Mat& z) + + :param Func: This row-vector corresponds to :math:`c` in the LP problem formulation (see above). + + :param Constr: *m*-by-*n\+1* matrix, whose rightmost column corresponds to :math:`b` in formulation above and the remaining to :math:`A`. + + :param z: The solution will be returned here as a row-vector - it corresponds to (transposed) :math:`c` in the formulation above. + + :return: One of the return codes: + +:: + + //!the return codes for solveLP() function + enum + { + SOLVELP_UNBOUNDED = -2, //problem is unbounded (target function can achieve arbitrary high values) + SOLVELP_UNFEASIBLE = -1, //problem is unfeasible (there are no points that satisfy all the constraints imposed) + SOLVELP_SINGLE = 0, //there is only one maximum for target function + SOLVELP_MULTI = 1 //there are multiple maxima for target function - the arbitrary one is returned + }; diff --git a/modules/optim/doc/optim.rst b/modules/optim/doc/optim.rst new file mode 100644 index 0000000000..bead2122a4 --- /dev/null +++ b/modules/optim/doc/optim.rst @@ -0,0 +1,10 @@ +************************************** +optim. Generic numerical optimization +************************************** + +.. highlight:: cpp + +.. toctree:: + :maxdepth: 2 + + linear_programming diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index f4a639f8bb..f40456c1a6 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -47,67 +47,77 @@ #include "opencv2/core.hpp" #include "opencv2/core/mat.hpp" -/*! \namespace cv - Namespace where all the C++ OpenCV functionality resides - */ +//uncomment the next line to print the debug info +//#define ALEX_DEBUG + namespace cv{namespace optim { //! generic class for optimization algorithms */ class CV_EXPORTS Solver : public Algorithm /* Algorithm is the base OpenCV class */ { - public: - class CV_EXPORTS Function - { - public: + public: + class CV_EXPORTS Function + { + public: virtual ~Function(){} virtual double calc(InputArray args) const = 0; - }; - class CV_EXPORTS Constraints - { - public: + }; + class CV_EXPORTS Constraints + { + public: virtual ~Constraints(){} - }; + }; - //! could be reused for all the generic algorithms like downhill simplex. Return value is the maximum value of a function*/ - virtual double solve(const Function& F,const Constraints& C, OutputArray result) const = 0; + //! could be reused for all the generic algorithms like downhill simplex. Return value is the maximum value of a function*/ + virtual double solve(const Function& F,const Constraints& C, OutputArray result) const = 0; - /*virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0;*/ + /*virtual void setTermCriteria(const TermCriteria& criteria) = 0; + virtual TermCriteria getTermCriteria() = 0;*/ - // more detailed API to be defined later ... + // more detailed API to be defined later ... }; class CV_EXPORTS LPSolver : public Solver { public: - class CV_EXPORTS LPFunction:public Solver::Function - { - Mat z; - public: - //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ - LPFunction(Mat z_in):z(z_in){} - ~LPFunction(){}; - const Mat& getz()const{return z;} - double calc(InputArray args)const; - }; + class CV_EXPORTS LPFunction:public Solver::Function + { + Mat z; + public: + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ + LPFunction(Mat z_in):z(z_in){} + ~LPFunction(){}; + const Mat& getz()const{return z;} + double calc(InputArray args)const; + }; - //!This class represents constraints for linear problem. There are two matrix stored: m-by-n matrix A and n-by-1 column-vector b. - //!What this represents is the set of constraints Ax\leq b and x\geq 0. It can be shown that any set of linear constraints can be converted - //!this form and **we shall create various constructors for this class that will perform these conversions**. - class CV_EXPORTS LPConstraints:public Solver::Constraints - { - Mat A,b; - public: - ~LPConstraints(){}; - //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ - LPConstraints(Mat A_in, Mat b_in):A(A_in),b(b_in){} - const Mat& getA()const{return A;} - const Mat& getb()const{return b;} - }; + //!This class represents constraints for linear problem. There are two matrix stored: m-by-n matrix A and n-by-1 column-vector b. + //!What this represents is the set of constraints Ax\leq b and x\geq 0. It can be shown that any set of linear constraints can be converted + //!this form and **we shall create various constructors for this class that will perform these conversions**. + class CV_EXPORTS LPConstraints:public Solver::Constraints + { + Mat A,b; + public: + ~LPConstraints(){}; + //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ + LPConstraints(Mat A_in, Mat b_in):A(A_in),b(b_in){} + const Mat& getA()const{return A;} + const Mat& getb()const{return b;} + }; - LPSolver(){} - double solve(const Function& F,const Constraints& C, OutputArray result)const; + LPSolver(){} + double solve(const Function& F,const Constraints& C, OutputArray result)const; }; + +//!the return codes for solveLP() function +enum +{ + SOLVELP_UNBOUNDED = -2, //problem is unbounded (target function can achieve arbitrary high values) + SOLVELP_UNFEASIBLE = -1, //problem is unfeasible (there are no points that satisfy all the constraints imposed) + SOLVELP_SINGLE = 0, //there is only one maximum for target function + SOLVELP_MULTI = 1 //there are multiple maxima for target function - the arbitrary one is returned +}; + CV_EXPORTS_W int solveLP(const Mat& Func, const Mat& Constr, Mat& z); }}// cv diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index b56dc3e3a6..1e80dfaf00 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -2,73 +2,87 @@ #include "precomp.hpp" #include #include +#include namespace cv{namespace optim{ using std::vector; -double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ +const void dprintf(const char* format,...){ +#ifdef ALEX_DEBUG + va_list args; + va_start (args,format); + vprintf(format,args); + va_end(args); +#endif +} +double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ return 0.0; } double LPSolver::LPFunction::calc(InputArray args)const{ - printf("call to LPFunction::calc()\n"); + dprintf("call to LPFunction::calc()\n"); return 0.0; } -void print_matrix(const Mat& X){ - printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); + + +void const print_matrix(const Mat& X){ +#ifdef ALEX_DEBUG + dprintf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); for(int i=0;i(i,j)); + dprintf("%g, ",X.at(i,j)); } - printf("]\n"); + dprintf("]\n"); } +#endif } -void print_simplex_state(const Mat& c,const Mat&b,double v,const vector& N,const vector& B){ - printf("\tprint simplex state\n"); - printf("v=%g\n",v); +void const print_simplex_state(const Mat& c,const Mat&b,double v,const vector& N,const vector& B){ +#ifdef ALEX_DEBUG + dprintf("\tprint simplex state\n"); - printf("here c goes\n"); + dprintf("v=%g\n",v); + + dprintf("here c goes\n"); print_matrix(c); - printf("non-basic: "); + dprintf("non-basic: "); for (std::vector::const_iterator it = N.begin() ; it != N.end(); ++it){ - printf("%d, ",*it); + dprintf("%d, ",*it); } - printf("\n"); + dprintf("\n"); - printf("here b goes\n"); + dprintf("here b goes\n"); print_matrix(b); - printf("basic: "); + dprintf("basic: "); for (std::vector::const_iterator it = B.begin() ; it != B.end(); ++it){ - printf("%d, ",*it); + dprintf("%d, ",*it); } - printf("\n"); + dprintf("\n"); +#endif } -namespace solveLP_aux{ - /**Due to technical considerations, the format of input b and c is somewhat special: - *both b and c should be one column bigger than corresponding b and c of linear problem and the leftmost column will be used internally - by this procedure - it should not be cleaned before the call to procedure and may contain mess after - it also initializes N and B and does not make any assumptions about their init values - * @return -1 if problem is unfeasible, 0 if feasible. - */ - int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); - inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); - /**@return -2 means the problem is unbdd, 1 means multiple solutions, 0 means successful. - */ - int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); - void swap_columns(Mat_& A,int col1,int col2); -} +/**Due to technical considerations, the format of input b and c is somewhat special: + *both b and c should be one column bigger than corresponding b and c of linear problem and the leftmost column will be used internally + by this procedure - it should not be cleaned before the call to procedure and may contain mess after + it also initializes N and B and does not make any assumptions about their init values + * @return SOLVELP_UNFEASIBLE if problem is unfeasible, 0 if feasible. +*/ +const int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); +const inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); +/**@return SOLVELP_UNBOUNDED means the problem is unbdd, SOLVELP_MULTI means multiple solutions, SOLVELP_SINGLE means one solution. + */ +const int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); +const void swap_columns(Mat_& A,int col1,int col2); //return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ - printf("call to solveLP\n"); + dprintf("call to solveLP\n"); - //sanity check (size, type, no. of channels) (and throw exception, if appropriate) + //sanity check (size, type, no. of channels) CV_Assert(Func.type()==CV_64FC1); CV_Assert(Constr.type()==CV_64FC1); CV_Assert(Func.rows==1); @@ -82,15 +96,15 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ double v=0; vector N,B; - if(solveLP_aux::initialize_simplex(bigC,bigB,v,N,B)==-1){ - return -1; + if(initialize_simplex(bigC,bigB,v,N,B)==SOLVELP_UNFEASIBLE){ + return SOLVELP_UNFEASIBLE; } Mat_ c=bigC.colRange(1,bigC.cols), b=bigB.colRange(1,bigB.cols); int res=0; - if((res=solveLP_aux::inner_simplex(c,b,v,N,B))==-2){ - return -2; + if((res=inner_simplex(c,b,v,N,B))==SOLVELP_UNBOUNDED){ + return SOLVELP_UNBOUNDED; } //return the optimal solution @@ -109,7 +123,7 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ return res; } -int solveLP_aux::initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ +const int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ N.resize(c.cols); N[0]=0; for (std::vector::iterator it = N.begin()+1 ; it != N.end(); ++it){ @@ -147,21 +161,21 @@ int solveLP_aux::initialize_simplex(Mat_& c, Mat_& b,double& v,v print_simplex_state(c,b,v,N,B); - printf("\tWE MAKE PIVOT\n"); + dprintf("\tWE MAKE PIVOT\n"); pivot(c,b,v,N,B,k,0); print_simplex_state(c,b,v,N,B); inner_simplex(c,b,v,N,B); - printf("\tAFTER INNER_SIMPLEX\n"); + dprintf("\tAFTER INNER_SIMPLEX\n"); print_simplex_state(c,b,v,N,B); vector::iterator it=std::find(B.begin(),B.end(),0); if(it!=B.end()){ int it_offset=it-B.begin(); if(b(it_offset,b.cols-1)>0){ - return -1; + return SOLVELP_UNFEASIBLE; } pivot(c,b,v,N,B,it_offset,0); } @@ -172,7 +186,7 @@ int solveLP_aux::initialize_simplex(Mat_& c, Mat_& b,double& v,v swap_columns(c,it_offset,0); swap_columns(b,it_offset,0); - printf("after swaps\n"); + dprintf("after swaps\n"); print_simplex_state(c,b,v,N,B); //start from 1, because we ignore x_0 @@ -180,14 +194,14 @@ int solveLP_aux::initialize_simplex(Mat_& c, Mat_& b,double& v,v v=0; for(int i=1;i& c, Mat_& b,double& v,v } } - printf("after restore\n"); + dprintf("after restore\n"); print_simplex_state(c,b,v,N,B); N.erase(N.begin()); return 0; } -int solveLP_aux::inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ +const int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ int count=0; while(1){ - printf("iteration #%d\n",count++); + dprintf("iteration #%d\n",count++); - MatIterator_ pos_ptr; + static MatIterator_ pos_ptr; int e=-1,pos_ctr=0,min_var=INT_MAX; bool all_nonzero=true; for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){ @@ -223,21 +237,15 @@ int solveLP_aux::inner_simplex(Mat_& c, Mat_& b,double& v,vector } } if(e==-1){ - printf("hello from e==-1\n"); + dprintf("hello from e==-1\n"); print_matrix(c); if(all_nonzero==true){ - return 0; + return SOLVELP_SINGLE; }else{ - return 1; + return SOLVELP_MULTI; } } - - /*for(pos_ptr=c.begin();(*pos_ptr<=0) && pos_ptr!=c.end();pos_ptr++,e++);//TODO: select the smallest index var w/ pos coef - if(pos_ptr==c.end()){ - return 0; - }*/ - int l=-1; min_var=INT_MAX; double min=DBL_MAX; @@ -259,30 +267,29 @@ int solveLP_aux::inner_simplex(Mat_& c, Mat_& b,double& v,vector } } if(l==-1){ - //unbounded - return -2; + return SOLVELP_UNBOUNDED; } - printf("the tightest constraint is in row %d with %g\n",l,min); + dprintf("the tightest constraint is in row %d with %g\n",l,min); - solveLP_aux::pivot(c,b,v,N,B,l,e); + pivot(c,b,v,N,B,l,e); - printf("objective, v=%g\n",v); + dprintf("objective, v=%g\n",v); print_matrix(c); - printf("constraints\n"); + dprintf("constraints\n"); print_matrix(b); - printf("non-basic: "); + dprintf("non-basic: "); for (std::vector::iterator it = N.begin() ; it != N.end(); ++it){ - printf("%d, ",*it); + dprintf("%d, ",*it); } - printf("\nbasic: "); + dprintf("\nbasic: "); for (std::vector::iterator it = B.begin() ; it != B.end(); ++it){ - printf("%d, ",*it); + dprintf("%d, ",*it); } - printf("\n"); + dprintf("\n"); } } -inline void solveLP_aux::pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ +const inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ double coef=b(leaving_index,entering_index); for(int i=0;i& c,Mat_& b,double& v,vector< c(0,i)-=coef*b(leaving_index,i); } } - printf("v was %g\n",v); + dprintf("v was %g\n",v); v+=coef*b(leaving_index,b.cols-1); int tmp=N[entering_index]; @@ -322,7 +329,7 @@ inline void solveLP_aux::pivot(Mat_& c,Mat_& b,double& v,vector< B[leaving_index]=tmp; } -void solveLP_aux::swap_columns(Mat_& A,int col1,int col2){ +const inline void swap_columns(Mat_& A,int col1,int col2){ for(int i=0;i Date: Thu, 11 Jul 2013 09:31:10 +0300 Subject: [PATCH 08/22] Preparation for pull request Additional cleaning for simplex method, removing the parts that are currently unused. Removing developer's notes. Trying to reach production level. --- modules/optim/include/opencv2/optim.hpp | 57 ------------------------- modules/optim/src/lpsolver.cpp | 14 ------ modules/optim/test/test_lpsolver.cpp | 20 --------- 3 files changed, 91 deletions(-) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index f40456c1a6..a50af74112 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -52,63 +52,6 @@ namespace cv{namespace optim { -//! generic class for optimization algorithms */ -class CV_EXPORTS Solver : public Algorithm /* Algorithm is the base OpenCV class */ -{ - public: - class CV_EXPORTS Function - { - public: - virtual ~Function(){} - virtual double calc(InputArray args) const = 0; - }; - class CV_EXPORTS Constraints - { - public: - virtual ~Constraints(){} - }; - - //! could be reused for all the generic algorithms like downhill simplex. Return value is the maximum value of a function*/ - virtual double solve(const Function& F,const Constraints& C, OutputArray result) const = 0; - - /*virtual void setTermCriteria(const TermCriteria& criteria) = 0; - virtual TermCriteria getTermCriteria() = 0;*/ - - // more detailed API to be defined later ... -}; - -class CV_EXPORTS LPSolver : public Solver -{ -public: - class CV_EXPORTS LPFunction:public Solver::Function - { - Mat z; - public: - //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of z_in.*/ - LPFunction(Mat z_in):z(z_in){} - ~LPFunction(){}; - const Mat& getz()const{return z;} - double calc(InputArray args)const; - }; - - //!This class represents constraints for linear problem. There are two matrix stored: m-by-n matrix A and n-by-1 column-vector b. - //!What this represents is the set of constraints Ax\leq b and x\geq 0. It can be shown that any set of linear constraints can be converted - //!this form and **we shall create various constructors for this class that will perform these conversions**. - class CV_EXPORTS LPConstraints:public Solver::Constraints - { - Mat A,b; - public: - ~LPConstraints(){}; - //! Note, that this class is supposed to be immutable, so it's ok to make only a shallow copy of A_in and b_in.*/ - LPConstraints(Mat A_in, Mat b_in):A(A_in),b(b_in){} - const Mat& getA()const{return A;} - const Mat& getb()const{return b;} - }; - - LPSolver(){} - double solve(const Function& F,const Constraints& C, OutputArray result)const; -}; - //!the return codes for solveLP() function enum { diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 1e80dfaf00..a0bece30e8 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -16,16 +16,6 @@ const void dprintf(const char* format,...){ #endif } -double LPSolver::solve(const Function& F,const Constraints& C, OutputArray result)const{ - return 0.0; -} - -double LPSolver::LPFunction::calc(InputArray args)const{ - dprintf("call to LPFunction::calc()\n"); - return 0.0; -} - - void const print_matrix(const Mat& X){ #ifdef ALEX_DEBUG dprintf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); @@ -337,7 +327,3 @@ const inline void swap_columns(Mat_& A,int col1,int col2){ } } }} -/*FIXME (possible optimizations) - * use iterator-style (as in ddc0010e7... commit version of this file) - * remove calls to pivot inside the while-loops - */ diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp index 8d14bf9d50..bcab3fa1c4 100644 --- a/modules/optim/test/test_lpsolver.cpp +++ b/modules/optim/test/test_lpsolver.cpp @@ -112,23 +112,3 @@ TEST(Optim_LpSolver, regression_cycling){ //ASSERT_EQ(res,1); } } - -//TODO -// get optimal solution from initial (0,0,...,0) - DONE -// milestone: pass first test (wo initial solution) - DONE - // - // ??how_check_multiple_solutions & pass_test - DONE - // Blands_rule - DONE - // (assert, assign) - DONE - // - // (&1tests on cycling) - // make_more_clear - // wrap in OOP - // - // non-trivial tests - // pull-request - // - // study hill and other algos - // -// ??how to get smallest l2 norm -// FUTURE: compress&debug-> more_tests(Cormen) -> readNumRecipes-> fast&stable || hill_climbing From fe6a7e935db6c2f1cf669d0a0e5c0e73a4a1d8ab Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 11 Jul 2013 09:52:13 +0300 Subject: [PATCH 09/22] Fix qualifiers on aux functions for solveLP() Change qualifiers on auxiliary functions (for solveLP() procedure) from const (that does not have much sense) to static (that makes them invisible for outside world and hopefully exacerbates optimization). --- modules/optim/src/lpsolver.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index a0bece30e8..7dc9f272f4 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -7,7 +7,7 @@ namespace cv{namespace optim{ using std::vector; -const void dprintf(const char* format,...){ +static void dprintf(const char* format,...){ #ifdef ALEX_DEBUG va_list args; va_start (args,format); @@ -16,7 +16,7 @@ const void dprintf(const char* format,...){ #endif } -void const print_matrix(const Mat& X){ +static void print_matrix(const Mat& X){ #ifdef ALEX_DEBUG dprintf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); for(int i=0;i& N,const vector& B){ +static void print_simplex_state(const Mat& c,const Mat&b,double v,const vector& N,const vector& B){ #ifdef ALEX_DEBUG dprintf("\tprint simplex state\n"); @@ -61,12 +61,12 @@ void const print_simplex_state(const Mat& c,const Mat&b,double v,const vector& c, Mat_& b,double& v,vector& N,vector& B); -const inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); +static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); +static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); /**@return SOLVELP_UNBOUNDED means the problem is unbdd, SOLVELP_MULTI means multiple solutions, SOLVELP_SINGLE means one solution. */ -const int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); -const void swap_columns(Mat_& A,int col1,int col2); +static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); +static void swap_columns(Mat_& A,int col1,int col2); //return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ @@ -113,7 +113,7 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ return res; } -const int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ +static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ N.resize(c.cols); N[0]=0; for (std::vector::iterator it = N.begin()+1 ; it != N.end(); ++it){ @@ -207,7 +207,7 @@ const int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& c, Mat_& b,double& v,vector& N,vector& B){ +static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ int count=0; while(1){ dprintf("iteration #%d\n",count++); @@ -279,7 +279,7 @@ const int inner_simplex(Mat_& c, Mat_& b,double& v,vector& } } -const inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ +static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ double coef=b(leaving_index,entering_index); for(int i=0;i& c,Mat_& b,double& v,vector& N B[leaving_index]=tmp; } -const inline void swap_columns(Mat_& A,int col1,int col2){ +static inline void swap_columns(Mat_& A,int col1,int col2){ for(int i=0;i Date: Thu, 11 Jul 2013 12:29:55 +0300 Subject: [PATCH 10/22] Fixed the warnings Fixed the code so to eliminate warnings related to shadowing and unused parameters. In some settings, these warnings may be treated as an errors and lead to failed build. Suggested by Nikita Manovich. --- modules/optim/src/lpsolver.cpp | 170 ++++++++++++++++----------------- 1 file changed, 82 insertions(+), 88 deletions(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 7dc9f272f4..dd587f0f01 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -7,53 +7,46 @@ namespace cv{namespace optim{ using std::vector; -static void dprintf(const char* format,...){ #ifdef ALEX_DEBUG - va_list args; - va_start (args,format); - vprintf(format,args); - va_end(args); +#define dprintf(x) printf x +#define print_matrix(x) do{\ + printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols);\ + for(int i=0;i<(x).rows;i++){\ + printf("\t[");\ + for(int j=0;j<(x).cols;j++){\ + printf("%g, ",(x).at(i,j));\ + }\ + printf("]\n");\ + }\ +}while(0) +#define print_simplex_state(c,b,v,N,B) do{\ + printf("\tprint simplex state\n");\ + \ + printf("v=%g\n",(v));\ + \ + printf("here c goes\n");\ + print_matrix((c));\ + \ + printf("non-basic: ");\ + for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){\ + printf("%d, ",*it);\ + }\ + printf("\n");\ + \ + printf("here b goes\n");\ + print_matrix((b));\ + printf("basic: ");\ + \ + for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){\ + printf("%d, ",*it);\ + }\ + printf("\n");\ +}while(0) +#else +#define dprintf(x) do {} while (0) +#define print_matrix(x) do {} while (0) +#define print_simplex_state(c,b,v,N,B) do {} while (0) #endif -} - -static void print_matrix(const Mat& X){ -#ifdef ALEX_DEBUG - dprintf("\ttype:%d vs %d,\tsize: %d-on-%d\n",X.type(),CV_64FC1,X.rows,X.cols); - for(int i=0;i(i,j)); - } - dprintf("]\n"); - } -#endif -} - -static void print_simplex_state(const Mat& c,const Mat&b,double v,const vector& N,const vector& B){ -#ifdef ALEX_DEBUG - dprintf("\tprint simplex state\n"); - - dprintf("v=%g\n",v); - - dprintf("here c goes\n"); - print_matrix(c); - - dprintf("non-basic: "); - for (std::vector::const_iterator it = N.begin() ; it != N.end(); ++it){ - dprintf("%d, ",*it); - } - dprintf("\n"); - - dprintf("here b goes\n"); - print_matrix(b); - dprintf("basic: "); - - for (std::vector::const_iterator it = B.begin() ; it != B.end(); ++it){ - dprintf("%d, ",*it); - } - dprintf("\n"); -#endif -} /**Due to technical considerations, the format of input b and c is somewhat special: *both b and c should be one column bigger than corresponding b and c of linear problem and the leftmost column will be used internally @@ -70,7 +63,7 @@ static void swap_columns(Mat_& A,int col1,int col2); //return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ - dprintf("call to solveLP\n"); + dprintf(("call to solveLP\n")); //sanity check (size, type, no. of channels) CV_Assert(Func.type()==CV_64FC1); @@ -151,56 +144,57 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< print_simplex_state(c,b,v,N,B); - dprintf("\tWE MAKE PIVOT\n"); + dprintf(("\tWE MAKE PIVOT\n")); pivot(c,b,v,N,B,k,0); print_simplex_state(c,b,v,N,B); inner_simplex(c,b,v,N,B); - dprintf("\tAFTER INNER_SIMPLEX\n"); + dprintf(("\tAFTER INNER_SIMPLEX\n")); print_simplex_state(c,b,v,N,B); - vector::iterator it=std::find(B.begin(),B.end(),0); - if(it!=B.end()){ - int it_offset=it-B.begin(); - if(b(it_offset,b.cols-1)>0){ + vector::iterator iterator=std::find(B.begin(),B.end(),0); + if(iterator!=B.end()){ + int iterator_offset=iterator-B.begin(); + if(b(iterator_offset,b.cols-1)>0){ return SOLVELP_UNFEASIBLE; } - pivot(c,b,v,N,B,it_offset,0); + pivot(c,b,v,N,B,iterator_offset,0); } - it=std::find(N.begin(),N.end(),0); - int it_offset=it-N.begin(); - std::iter_swap(it,N.begin()); - swap_columns(c,it_offset,0); - swap_columns(b,it_offset,0); + { + iterator=std::find(N.begin(),N.end(),0); + int iterator_offset=iterator-N.begin(); + std::iter_swap(iterator,N.begin()); + swap_columns(c,iterator_offset,0); + swap_columns(b,iterator_offset,0); + } - dprintf("after swaps\n"); + dprintf(("after swaps\n")); print_simplex_state(c,b,v,N,B); //start from 1, because we ignore x_0 c=0; v=0; - for(int i=1;i& c, Mat_& b,double& v,vector< static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ int count=0; while(1){ - dprintf("iteration #%d\n",count++); + dprintf(("iteration #%d\n",count++)); static MatIterator_ pos_ptr; int e=-1,pos_ctr=0,min_var=INT_MAX; @@ -227,7 +221,7 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& } } if(e==-1){ - dprintf("hello from e==-1\n"); + dprintf(("hello from e==-1\n")); print_matrix(c); if(all_nonzero==true){ return SOLVELP_SINGLE; @@ -259,33 +253,33 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& if(l==-1){ return SOLVELP_UNBOUNDED; } - dprintf("the tightest constraint is in row %d with %g\n",l,min); + dprintf(("the tightest constraint is in row %d with %g\n",l,min)); pivot(c,b,v,N,B,l,e); - dprintf("objective, v=%g\n",v); + dprintf(("objective, v=%g\n",v)); print_matrix(c); - dprintf("constraints\n"); + dprintf(("constraints\n")); print_matrix(b); - dprintf("non-basic: "); + dprintf(("non-basic: ")); for (std::vector::iterator it = N.begin() ; it != N.end(); ++it){ - dprintf("%d, ",*it); + dprintf(("%d, ",*it)); } - dprintf("\nbasic: "); + dprintf(("\nbasic: ")); for (std::vector::iterator it = B.begin() ; it != B.end(); ++it){ - dprintf("%d, ",*it); + dprintf(("%d, ",*it)); } - dprintf("\n"); + dprintf(("\n")); } } static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ - double coef=b(leaving_index,entering_index); + double Coef=b(leaving_index,entering_index); for(int i=0;i& c,Mat_& b,double& v,vector& } //objective function - coef=c(0,entering_index); + Coef=c(0,entering_index); for(int i=0;i<(b.cols-1);i++){ if(i==entering_index){ - c(0,i)=-coef*b(leaving_index,i); + c(0,i)=-Coef*b(leaving_index,i); }else{ - c(0,i)-=coef*b(leaving_index,i); + c(0,i)-=Coef*b(leaving_index,i); } } - dprintf("v was %g\n",v); - v+=coef*b(leaving_index,b.cols-1); + dprintf(("v was %g\n",v)); + v+=Coef*b(leaving_index,b.cols-1); int tmp=N[entering_index]; N[entering_index]=B[leaving_index]; From e9b432b1d9515e0f136d590920188555cea94c39 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 11 Jul 2013 14:43:48 +0300 Subject: [PATCH 11/22] Fixing the warnings Fixed all of the warnings. --- modules/optim/src/lpsolver.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index dd587f0f01..28b7b461b2 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -204,7 +204,8 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ int count=0; while(1){ - dprintf(("iteration #%d\n",count++)); + dprintf(("iteration #%d\n",count)); + count++; static MatIterator_ pos_ptr; int e=-1,pos_ctr=0,min_var=INT_MAX; @@ -234,7 +235,6 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& min_var=INT_MAX; double min=DBL_MAX; int row_it=0; - double ite=0; MatIterator_ min_row_ptr=b.begin(); for(MatIterator_ it=b.begin();it!=b.end();it+=b.cols,row_it++){ double myite=0; @@ -244,7 +244,6 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& if(val Date: Thu, 11 Jul 2013 22:05:14 +0300 Subject: [PATCH 12/22] Convenience fixes Attempting to fix issues pointed out by Vadim Pisarevsky during the pull request review. In particular, the following things are done: *) The mechanism of debug info printing is changed and made more procedure-style than the previous macro-style *) z in solveLP() is now returned as a column-vector *) Func parameter of solveLP() is now allowed to be column-vector, in which case it is understood to be the transpose of what we need *) Func and Constr now can contain floats, not only doubles (in the former case the conversion is done via convertTo()) *)different constructor to allocate space for z in solveLP() is used, making the size of z more explicit (this is just a notation change, not functional, both constructors are achieving the same goal) *) (big) mat.hpp and iostream headers are moved to precomp-headers from optim.hpp --- modules/optim/doc/linear_programming.rst | 6 +- modules/optim/include/opencv2/optim.hpp | 4 - modules/optim/src/lpsolver.cpp | 103 ++++++++++++++--------- modules/optim/src/precomp.hpp | 2 + modules/optim/test/test_lpsolver.cpp | 18 ++-- modules/optim/test/test_precomp.hpp | 2 + 6 files changed, 77 insertions(+), 58 deletions(-) diff --git a/modules/optim/doc/linear_programming.rst b/modules/optim/doc/linear_programming.rst index fbc1d04e33..946df9e955 100644 --- a/modules/optim/doc/linear_programming.rst +++ b/modules/optim/doc/linear_programming.rst @@ -28,11 +28,11 @@ by T. H. Cormen, C. E. Leiserson, R. L. Rivest and Clifford Stein. In particular .. ocv:function:: int optim::solveLP(const Mat& Func, const Mat& Constr, Mat& z) - :param Func: This row-vector corresponds to :math:`c` in the LP problem formulation (see above). + :param Func: This row-vector corresponds to :math:`c` in the LP problem formulation (see above). It should contain 32- or 64-bit floating point numbers. As a convenience, column-vector may be also submitted, in the latter case it is understood to correspond to :math:`c^T`. - :param Constr: *m*-by-*n\+1* matrix, whose rightmost column corresponds to :math:`b` in formulation above and the remaining to :math:`A`. + :param Constr: *m*-by-*n\+1* matrix, whose rightmost column corresponds to :math:`b` in formulation above and the remaining to :math:`A`. It should containt 32- or 64-bit floating point numbers. - :param z: The solution will be returned here as a row-vector - it corresponds to (transposed) :math:`c` in the formulation above. + :param z: The solution will be returned here as a column-vector - it corresponds to :math:`c` in the formulation above. It will contain 64-bit floating point numbers. :return: One of the return codes: diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index a50af74112..2e225e805c 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -43,10 +43,6 @@ #ifndef __OPENCV_OPTIM_HPP__ #define __OPENCV_OPTIM_HPP__ -#include -#include "opencv2/core.hpp" -#include "opencv2/core/mat.hpp" - //uncomment the next line to print the debug info //#define ALEX_DEBUG diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 28b7b461b2..8377e5c06c 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -9,39 +9,39 @@ using std::vector; #ifdef ALEX_DEBUG #define dprintf(x) printf x -#define print_matrix(x) do{\ - printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols);\ - for(int i=0;i<(x).rows;i++){\ - printf("\t[");\ - for(int j=0;j<(x).cols;j++){\ - printf("%g, ",(x).at(i,j));\ - }\ - printf("]\n");\ - }\ -}while(0) -#define print_simplex_state(c,b,v,N,B) do{\ - printf("\tprint simplex state\n");\ - \ - printf("v=%g\n",(v));\ - \ - printf("here c goes\n");\ - print_matrix((c));\ - \ - printf("non-basic: ");\ - for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){\ - printf("%d, ",*it);\ - }\ - printf("\n");\ - \ - printf("here b goes\n");\ - print_matrix((b));\ - printf("basic: ");\ - \ - for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){\ - printf("%d, ",*it);\ - }\ - printf("\n");\ -}while(0) +static void print_matrix(const Mat& x){ + printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols); + for(int i=0;i<(x).rows;i++){ + printf("\t["); + for(int j=0;j<(x).cols;j++){ + printf("%g, ",(x).at(i,j)); + } + printf("]\n"); + } +} +static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector N,const std::vector B){ + printf("\tprint simplex state\n"); + + printf("v=%g\n",(v)); + + printf("here c goes\n"); + print_matrix((c)); + + printf("non-basic: "); + for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); + + printf("here b goes\n"); + print_matrix((b)); + printf("basic: "); + + for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); +} #else #define dprintf(x) do {} while (0) #define print_matrix(x) do {} while (0) @@ -66,16 +66,36 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ dprintf(("call to solveLP\n")); //sanity check (size, type, no. of channels) - CV_Assert(Func.type()==CV_64FC1); - CV_Assert(Constr.type()==CV_64FC1); - CV_Assert(Func.rows==1); - CV_Assert(Constr.cols-Func.cols==1); + CV_Assert(Func.type()==CV_64FC1 || Func.type()==CV_32FC1); + CV_Assert(Constr.type()==CV_64FC1 || Constr.type()==CV_32FC1); + CV_Assert((Func.rows==1 && (Constr.cols-Func.cols==1))|| + (Func.cols==1 && (Constr.cols-Func.rows==1))); //copy arguments for we will shall modify them - Mat_ bigC=Mat_(1,Func.cols+1), + Mat_ bigC=Mat_(1,(Func.rows==1?Func.cols:Func.rows)+1), bigB=Mat_(Constr.rows,Constr.cols+1); - Func.copyTo(bigC.colRange(1,bigC.cols)); - Constr.copyTo(bigB.colRange(1,bigB.cols)); + if(Func.rows==1){ + Func.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1); + }else{ + dprintf(("hi from other branch\n")); + Mat_ slice=bigC.colRange(1,bigC.cols); + MatIterator_ slice_iterator=slice.begin(); + switch(Func.type()){ + case CV_64FC1: + for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ + * slice_iterator= *it; + } + break; + case CV_32FC1: + for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ + * slice_iterator= *it; + } + break; + } + print_matrix(Func); + print_matrix(bigC); + } + Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1); double v=0; vector N,B; @@ -91,8 +111,7 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ } //return the optimal solution - const int z_size[]={1,c.cols}; - z.create(2,z_size,CV_64FC1); + z.create(c.cols,1,CV_64FC1); MatIterator_ it=z.begin(); for(int i=1;i<=c.cols;i++,it++){ std::vector::iterator pos=B.begin(); diff --git a/modules/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp index 7aab572f88..60d2b5b2fa 100644 --- a/modules/optim/src/precomp.hpp +++ b/modules/optim/src/precomp.hpp @@ -43,6 +43,8 @@ #ifndef __OPENCV_PRECOMP_H__ #define __OPENCV_PRECOMP_H__ +#include "opencv2/core.hpp" +#include "opencv2/core/mat.hpp" #include "opencv2/optim.hpp" #endif diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp index bcab3fa1c4..68bc693f9d 100644 --- a/modules/optim/test/test_lpsolver.cpp +++ b/modules/optim/test/test_lpsolver.cpp @@ -1,17 +1,17 @@ #include "test_precomp.hpp" -#include "opencv2/optim.hpp" +#include TEST(Optim_LpSolver, regression_basic){ cv::Mat A,B,z,etalon_z; if(true){ //cormen's example #1 - A=(cv::Mat_(1,3)<<3,1,2); + A=(cv::Mat_(3,1)<<3,1,2); B=(cv::Mat_(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36); std::cout<<"here A goes\n"<(1,3)<<8,4,0); + etalon_z=(cv::Mat_(3,1)<<8,4,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } @@ -22,7 +22,7 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here A goes\n"<(1,2)<<20,0); + etalon_z=(cv::Mat_(2,1)<<20,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } @@ -33,7 +33,7 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here A goes\n"<(1,2)<<1,0); + etalon_z=(cv::Mat_(2,1)<<1,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } } @@ -48,7 +48,7 @@ TEST(Optim_LpSolver, regression_init_unfeasible){ std::cout<<"here A goes\n"<(1,3)<<1250,1000,0); + etalon_z=(cv::Mat_(3,1)<<1250,1000,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } } @@ -71,7 +71,7 @@ TEST(Optim_LpSolver, regression_multiple_solutions){ if(true){ //trivial example with multiple solutions - A=(cv::Mat_(1,2)<<1,1); + A=(cv::Mat_(2,1)<<1,1); B=(cv::Mat_(1,3)<<1,1,1); std::cout<<"here A goes\n"<(1,2)<<2,-1); + A=(cv::Mat_(2,1)<<2,-1); B=(cv::Mat_(2,3)<<2,-1,2,1,-5,-4); std::cout<<"here A goes\n"<(1,4)<<10,-57,-9,-24); + A=(cv::Mat_(4,1)<<10,-57,-9,-24); B=(cv::Mat_(3,5)<<0.5,-5.5,-2.5,9,0,0.5,-1.5,-0.5,1,0,1,0,0,0,1); std::cout<<"here A goes\n"< Date: Fri, 19 Jul 2013 03:09:39 +0300 Subject: [PATCH 13/22] Minor fixes In request to the comments for the pull request. --- modules/optim/include/opencv2/optim.hpp | 5 ++-- modules/optim/src/lpsolver.cpp | 36 ++++++++++++++----------- modules/optim/src/precomp.hpp | 2 -- modules/optim/test/test_precomp.hpp | 2 -- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 2e225e805c..84430361c8 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -43,11 +43,12 @@ #ifndef __OPENCV_OPTIM_HPP__ #define __OPENCV_OPTIM_HPP__ -//uncomment the next line to print the debug info -//#define ALEX_DEBUG +#include "opencv2/core.hpp" +#include namespace cv{namespace optim { + using namespace std; //!the return codes for solveLP() function enum { diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 8377e5c06c..909794ab06 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -1,51 +1,59 @@ -#include "opencv2/ts.hpp" #include "precomp.hpp" #include #include #include +#define ALEX_DEBUG + namespace cv{namespace optim{ using std::vector; +using namespace std; #ifdef ALEX_DEBUG #define dprintf(x) printf x static void print_matrix(const Mat& x){ - printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols); - for(int i=0;i<(x).rows;i++){ + printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",x.type(),CV_64FC1,x.rows,x.cols); + if(!true){ + //cout<(i,j)); + for(int j=0;j(i,j)); } printf("]\n"); } + } } static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector N,const std::vector B){ printf("\tprint simplex state\n"); - printf("v=%g\n",(v)); + printf("v=%g\n",v); printf("here c goes\n"); - print_matrix((c)); + print_matrix(c); printf("non-basic: "); - for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){ + for (std::vector::const_iterator it = N.begin() ; it != N.end(); ++it){ printf("%d, ",*it); } printf("\n"); printf("here b goes\n"); - print_matrix((b)); + print_matrix(b); printf("basic: "); - for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){ + for (std::vector::const_iterator it = B.begin() ; it != B.end(); ++it){ printf("%d, ",*it); } printf("\n"); } #else -#define dprintf(x) do {} while (0) -#define print_matrix(x) do {} while (0) -#define print_simplex_state(c,b,v,N,B) do {} while (0) +#define dprintf(x) +#define print_matrix(x) +#define print_simplex_state(c,b,v,N,B) #endif /**Due to technical considerations, the format of input b and c is somewhat special: @@ -199,13 +207,11 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< for(int I=1;I Date: Fri, 19 Jul 2013 12:34:33 +0300 Subject: [PATCH 14/22] Simplify printing procedures Use opencv's print() procedure in place of my own procedures to output matrices and std::vectors. Interestingly enough, operator<< does not work for matrices, when called from my .cpp files in src/ subfolder of the optim module, although it works when called from tests and stand-alone programs, compiled with opencv. I think, this requires investigation and, maybe, bug report. --- modules/optim/include/opencv2/optim.hpp | 1 - modules/optim/src/lpsolver.cpp | 54 +++++-------------------- 2 files changed, 9 insertions(+), 46 deletions(-) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 84430361c8..13ed865cdb 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -44,7 +44,6 @@ #define __OPENCV_OPTIM_HPP__ #include "opencv2/core.hpp" -#include namespace cv{namespace optim { diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 909794ab06..e746c39c55 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -12,20 +12,8 @@ using namespace std; #ifdef ALEX_DEBUG #define dprintf(x) printf x static void print_matrix(const Mat& x){ - printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",x.type(),CV_64FC1,x.rows,x.cols); - if(!true){ - //cout<(i,j)); - } - printf("]\n"); - } - } + print(x); + printf("\n"); } static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector N,const std::vector B){ printf("\tprint simplex state\n"); @@ -36,18 +24,14 @@ static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::ve print_matrix(c); printf("non-basic: "); - for (std::vector::const_iterator it = N.begin() ; it != N.end(); ++it){ - printf("%d, ",*it); - } + print(Mat(N)); printf("\n"); printf("here b goes\n"); print_matrix(b); printf("basic: "); - for (std::vector::const_iterator it = B.begin() ; it != B.end(); ++it){ - printf("%d, ",*it); - } + print(Mat(B)); printf("\n"); } #else @@ -85,23 +69,8 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ if(Func.rows==1){ Func.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1); }else{ - dprintf(("hi from other branch\n")); - Mat_ slice=bigC.colRange(1,bigC.cols); - MatIterator_ slice_iterator=slice.begin(); - switch(Func.type()){ - case CV_64FC1: - for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ - * slice_iterator= *it; - } - break; - case CV_32FC1: - for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ - * slice_iterator= *it; - } - break; - } - print_matrix(Func); - print_matrix(bigC); + Mat FuncT=Func.t(); + FuncT.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1); } Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1); double v=0; @@ -286,14 +255,9 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& dprintf(("constraints\n")); print_matrix(b); dprintf(("non-basic: ")); - for (std::vector::iterator it = N.begin() ; it != N.end(); ++it){ - dprintf(("%d, ",*it)); - } - dprintf(("\nbasic: ")); - for (std::vector::iterator it = B.begin() ; it != B.end(); ++it){ - dprintf(("%d, ",*it)); - } - dprintf(("\n")); + print_matrix(Mat(N)); + dprintf(("basic: ")); + print_matrix(Mat(B)); } } From c123974f420cebc3c39f103988d594df67903093 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Sat, 20 Jul 2013 15:14:02 +0300 Subject: [PATCH 15/22] Eliminated all the calls to std::find() This is done by keeping indexToRow vector, that keeps the information, opposite to those kept by N and B. That is, while N and B help to determine which variable corresponds to given column in column-vector c or row in matrix b, indexToRow helps to determine the corresponding row/column for a given variable. At this point, I'm waiting for comments from pull request reviewer and not working on any upgrades. Comments are appreciated, as usual. --- modules/optim/include/opencv2/optim.hpp | 1 - modules/optim/src/lpsolver.cpp | 68 +++++++++++++++---------- modules/optim/test/test_lpsolver.cpp | 13 ----- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index 13ed865cdb..0bbedad38f 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -47,7 +47,6 @@ namespace cv{namespace optim { - using namespace std; //!the return codes for solveLP() function enum { diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index e746c39c55..0690387ac7 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -3,11 +3,8 @@ #include #include -#define ALEX_DEBUG - namespace cv{namespace optim{ using std::vector; -using namespace std; #ifdef ALEX_DEBUG #define dprintf(x) printf x @@ -46,12 +43,14 @@ static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::ve it also initializes N and B and does not make any assumptions about their init values * @return SOLVELP_UNFEASIBLE if problem is unfeasible, 0 if feasible. */ -static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); -static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index); +static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow); +static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B,int leaving_index, + int entering_index,vector& indexToRow); /**@return SOLVELP_UNBOUNDED means the problem is unbdd, SOLVELP_MULTI means multiple solutions, SOLVELP_SINGLE means one solution. */ -static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B); +static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow); static void swap_columns(Mat_& A,int col1,int col2); +#define SWAP(type,a,b) {type tmp=(a);(a)=(b);(b)=tmp;} //return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm) int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ @@ -75,15 +74,16 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1); double v=0; vector N,B; + vector indexToRow; - if(initialize_simplex(bigC,bigB,v,N,B)==SOLVELP_UNFEASIBLE){ + if(initialize_simplex(bigC,bigB,v,N,B,indexToRow)==SOLVELP_UNFEASIBLE){ return SOLVELP_UNFEASIBLE; } Mat_ c=bigC.colRange(1,bigC.cols), b=bigB.colRange(1,bigB.cols); int res=0; - if((res=inner_simplex(c,b,v,N,B))==SOLVELP_UNBOUNDED){ + if((res=inner_simplex(c,b,v,N,B,indexToRow))==SOLVELP_UNBOUNDED){ return SOLVELP_UNBOUNDED; } @@ -92,17 +92,17 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ MatIterator_ it=z.begin(); for(int i=1;i<=c.cols;i++,it++){ std::vector::iterator pos=B.begin(); - if((pos=std::find(B.begin(),B.end(),i))==B.end()){ + if(indexToRow[i](pos-B.begin(),b.cols-1); + *it=b.at(indexToRow[i]-N.size(),b.cols-1); } } return res; } -static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ +static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow){ N.resize(c.cols); N[0]=0; for (std::vector::iterator it = N.begin()+1 ; it != N.end(); ++it){ @@ -113,6 +113,11 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< for (std::vector::iterator it = B.begin()+1 ; it != B.end(); ++it){ *it=it[-1]+1; } + indexToRow.resize(c.cols+b.rows); + indexToRow[0]=0; + for (std::vector::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){ + *it=it[-1]+1; + } v=0; int k=0; @@ -128,6 +133,9 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< if(b(k,b.cols-1)>=0){ N.erase(N.begin()); + for (std::vector::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){ + --(*it); + } return 0; } @@ -141,28 +149,29 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< print_simplex_state(c,b,v,N,B); dprintf(("\tWE MAKE PIVOT\n")); - pivot(c,b,v,N,B,k,0); + pivot(c,b,v,N,B,k,0,indexToRow); print_simplex_state(c,b,v,N,B); - inner_simplex(c,b,v,N,B); + inner_simplex(c,b,v,N,B,indexToRow); dprintf(("\tAFTER INNER_SIMPLEX\n")); print_simplex_state(c,b,v,N,B); - vector::iterator iterator=std::find(B.begin(),B.end(),0); - if(iterator!=B.end()){ - int iterator_offset=iterator-B.begin(); + if(indexToRow[0]>=N.size()){ + int iterator_offset=indexToRow[0]-N.size(); if(b(iterator_offset,b.cols-1)>0){ return SOLVELP_UNFEASIBLE; } - pivot(c,b,v,N,B,iterator_offset,0); + pivot(c,b,v,N,B,iterator_offset,0,indexToRow); } + vector::iterator iterator; { - iterator=std::find(N.begin(),N.end(),0); - int iterator_offset=iterator-N.begin(); + int iterator_offset=indexToRow[0]; + iterator=N.begin()+iterator_offset; std::iter_swap(iterator,N.begin()); + SWAP(int,indexToRow[*iterator],indexToRow[0]); swap_columns(c,iterator_offset,0); swap_columns(b,iterator_offset,0); } @@ -174,14 +183,14 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< c=0; v=0; for(int I=1;I& c, Mat_& b,double& v,vector< print_simplex_state(c,b,v,N,B); N.erase(N.begin()); + for (std::vector::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){ + --(*it); + } return 0; } -static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B){ +static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow){ int count=0; while(1){ dprintf(("iteration #%d\n",count)); @@ -248,7 +260,7 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& } dprintf(("the tightest constraint is in row %d with %g\n",l,min)); - pivot(c,b,v,N,B,l,e); + pivot(c,b,v,N,B,l,e,indexToRow); dprintf(("objective, v=%g\n",v)); print_matrix(c); @@ -261,7 +273,8 @@ static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& } } -static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, int leaving_index,int entering_index){ +static inline void pivot(Mat_& c,Mat_& b,double& v,vector& N,vector& B, + int leaving_index,int entering_index,vector& indexToRow){ double Coef=b(leaving_index,entering_index); for(int i=0;i& c,Mat_& b,double& v,vector& dprintf(("v was %g\n",v)); v+=Coef*b(leaving_index,b.cols-1); - int tmp=N[entering_index]; - N[entering_index]=B[leaving_index]; - B[leaving_index]=tmp; + SWAP(int,N[entering_index],B[leaving_index]); + SWAP(int,indexToRow[N[entering_index]],indexToRow[B[leaving_index]]); } static inline void swap_columns(Mat_& A,int col1,int col2){ diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp index 68bc693f9d..5a7f4c484e 100644 --- a/modules/optim/test/test_lpsolver.cpp +++ b/modules/optim/test/test_lpsolver.cpp @@ -81,19 +81,6 @@ TEST(Optim_LpSolver, regression_multiple_solutions){ ASSERT_EQ(res,1); ASSERT_EQ(z.dot(A),1); } - - if(false){ - //cormen's example from chapter about initialize_simplex - //online solver told it has inf many solutions, but I'm not sure - A=(cv::Mat_(2,1)<<2,-1); - B=(cv::Mat_(2,3)<<2,-1,2,1,-5,-4); - std::cout<<"here A goes\n"< Date: Mon, 22 Jul 2013 17:53:56 +0800 Subject: [PATCH 16/22] Fix the problem of haar caused by merge --- modules/ocl/doc/object_detection.rst | 19 +- modules/ocl/include/opencv2/ocl.hpp | 46 -- modules/ocl/perf/perf_haar.cpp | 53 +-- modules/ocl/src/haar.cpp | 639 +-------------------------- modules/ocl/src/precomp.hpp | 2 +- modules/ocl/test/test_objdetect.cpp | 56 +-- samples/ocl/facedetect.cpp | 31 +- 7 files changed, 55 insertions(+), 791 deletions(-) diff --git a/modules/ocl/doc/object_detection.rst b/modules/ocl/doc/object_detection.rst index 17eb62d0e5..ca0b6d1218 100644 --- a/modules/ocl/doc/object_detection.rst +++ b/modules/ocl/doc/object_detection.rst @@ -12,23 +12,20 @@ Cascade classifier class used for object detection. Supports HAAR cascade classi class CV_EXPORTS OclCascadeClassifier : public CascadeClassifier { public: - OclCascadeClassifier() {}; - ~OclCascadeClassifier() {}; - CvSeq *oclHaarDetectObjects(oclMat &gimg, CvMemStorage *storage, - double scaleFactor,int minNeighbors, - int flags, CvSize minSize = cvSize(0, 0), - CvSize maxSize = cvSize(0, 0)); + void detectMultiScale(oclMat &image, CV_OUT std::vector& faces, + double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, + Size minSize = Size(), Size maxSize = Size()); }; ocl::OclCascadeClassifier::oclHaarDetectObjects ------------------------------------------------------ -Returns the detected objects by a list of rectangles +Detects objects of different sizes in the input image. -.. ocv:function:: CvSeq* ocl::OclCascadeClassifier::oclHaarDetectObjects(oclMat &gimg, CvMemStorage *storage, double scaleFactor,int minNeighbors, int flags, CvSize minSize = cvSize(0, 0), CvSize maxSize = cvSize(0, 0)) +.. ocv:function:: void ocl::OclCascadeClassifier::detectMultiScale(oclMat &image, std::vector& faces, double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, Size minSize = Size(), Size maxSize = Size()) :param image: Matrix of type CV_8U containing an image where objects should be detected. - :param imageobjectsBuff: Buffer to store detected objects (rectangles). If it is empty, it is allocated with the defaultsize. If not empty, the function searches not more than N objects, where N = sizeof(objectsBufers data)/sizeof(cv::Rect). + :param faces: Vector of rectangles where each rectangle contains the detected object. :param scaleFactor: Parameter specifying how much the image size is reduced at each image scale. @@ -36,7 +33,9 @@ Returns the detected objects by a list of rectangles :param minSize: Minimum possible object size. Objects smaller than that are ignored. -Detects objects of different sizes in the input image,only tested for face detection now. The function returns the number of detected objects. + :param maxSize: Maximum possible object size. Objects larger than that are ignored. + +The function provides a very similar interface with that in CascadeClassifier class, except using oclMat as input image. ocl::MatchTemplateBuf --------------------- diff --git a/modules/ocl/include/opencv2/ocl.hpp b/modules/ocl/include/opencv2/ocl.hpp index 3da935275e..695fbb4082 100644 --- a/modules/ocl/include/opencv2/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl.hpp @@ -856,59 +856,13 @@ namespace cv //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////CascadeClassifier////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if 0 class CV_EXPORTS OclCascadeClassifier : public cv::CascadeClassifier { public: - OclCascadeClassifier() {}; - ~OclCascadeClassifier() {}; - - CvSeq* oclHaarDetectObjects(oclMat &gimg, CvMemStorage *storage, double scaleFactor, - int minNeighbors, int flags, CvSize minSize = cvSize(0, 0), CvSize maxSize = cvSize(0, 0)); - }; -#endif - -#if 0 - class CV_EXPORTS OclCascadeClassifierBuf : public cv::CascadeClassifier - { - public: - OclCascadeClassifierBuf() : - m_flags(0), initialized(false), m_scaleFactor(0), buffers(NULL) {} - - ~OclCascadeClassifierBuf() { release(); } - void detectMultiScale(oclMat &image, CV_OUT std::vector& faces, double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, Size minSize = Size(), Size maxSize = Size()); - void release(); - - private: - void Init(const int rows, const int cols, double scaleFactor, int flags, - const int outputsz, const size_t localThreads[], - Size minSize, Size maxSize); - void CreateBaseBufs(const int datasize, const int totalclassifier, const int flags, const int outputsz); - void CreateFactorRelatedBufs(const int rows, const int cols, const int flags, - const double scaleFactor, const size_t localThreads[], - Size minSize, Size maxSize); - void GenResult(CV_OUT std::vector& faces, const std::vector &rectList, const std::vector &rweights); - - int m_rows; - int m_cols; - int m_flags; - int m_loopcount; - int m_nodenum; - bool findBiggestObject; - bool initialized; - double m_scaleFactor; - Size m_minSize; - Size m_maxSize; - std::vector sizev; - std::vector scalev; - oclMat gimg1, gsum, gsqsum; - void * buffers; }; -#endif /////////////////////////////// Pyramid ///////////////////////////////////// CV_EXPORTS void pyrDown(const oclMat &src, oclMat &dst); diff --git a/modules/ocl/perf/perf_haar.cpp b/modules/ocl/perf/perf_haar.cpp index 372949521d..38e9d5e968 100644 --- a/modules/ocl/perf/perf_haar.cpp +++ b/modules/ocl/perf/perf_haar.cpp @@ -44,47 +44,8 @@ // //M*/ #include "precomp.hpp" - -#if 0 - ///////////// Haar //////////////////////// -namespace cv -{ -namespace ocl -{ -struct getRect -{ - Rect operator()(const CvAvgComp &e) const - { - return e.rect; - } -}; - -class CascadeClassifier_GPU : public OclCascadeClassifier -{ -public: - void detectMultiScale(oclMat &image, - CV_OUT std::vector& faces, - double scaleFactor = 1.1, - int minNeighbors = 3, int flags = 0, - Size minSize = Size(), - Size maxSize = Size()) - { - (void)maxSize; - MemStorage storage(cvCreateMemStorage(0)); - //CvMat img=image; - CvSeq *objs = oclHaarDetectObjects(image, storage, scaleFactor, minNeighbors, flags, minSize); - vector vecAvgComp; - Seq(objs).copyTo(vecAvgComp); - faces.resize(vecAvgComp.size()); - std::transform(vecAvgComp.begin(), vecAvgComp.end(), faces.begin(), getRect()); - } - -}; - -} -} PERFTEST(Haar) { Mat img = imread(abspath("basketball1.png"), IMREAD_GRAYSCALE); @@ -106,12 +67,12 @@ PERFTEST(Haar) SUBTEST << img.cols << "x" << img.rows << "; scale image"; CPU_ON; faceCascadeCPU.detectMultiScale(img, faces, - 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); + 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30)); CPU_OFF; vector oclfaces; - ocl::CascadeClassifier_GPU faceCascade; + ocl::OclCascadeClassifier faceCascade; if (!faceCascade.load(abspath("haarcascade_frontalface_alt.xml"))) { @@ -122,7 +83,7 @@ PERFTEST(Haar) WARMUP_ON; faceCascade.detectMultiScale(d_img, oclfaces, - 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); + 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30)); WARMUP_OFF; if(faces.size() == oclfaces.size()) @@ -134,14 +95,12 @@ PERFTEST(Haar) GPU_ON; faceCascade.detectMultiScale(d_img, oclfaces, - 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); + 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30)); GPU_OFF; GPU_FULL_ON; d_img.upload(img); faceCascade.detectMultiScale(d_img, oclfaces, - 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); + 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30)); GPU_FULL_OFF; -} - -#endif +} \ No newline at end of file diff --git a/modules/ocl/src/haar.cpp b/modules/ocl/src/haar.cpp index 6f028317d3..a8118dba60 100644 --- a/modules/ocl/src/haar.cpp +++ b/modules/ocl/src/haar.cpp @@ -20,7 +20,6 @@ // Jia Haipeng, jiahaipeng95@gmail.com // Wu Xinglong, wxl370@126.com // Wang Yao, bitwangyaoyao@gmail.com -// Sen Liu, swjtuls1987@126.com // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -54,8 +53,6 @@ using namespace cv; using namespace cv::ocl; -#if 0 - namespace cv { namespace ocl @@ -68,9 +65,9 @@ extern const char *haarobjectdetect_scaled2; } /* these settings affect the quality of detection: change with care */ -#define CV_ADJUST_FEATURES 1 -#define CV_ADJUST_WEIGHTS 0 - +#define CV_ADJUST_FEATURES 1 +#define CV_ADJUST_WEIGHTS 0 +#define CV_HAAR_FEATURE_MAX 3 typedef int sumtype; typedef double sqsumtype; @@ -679,14 +676,15 @@ static void gpuSetHaarClassifierCascade( CvHaarClassifierCascade *_cascade) } /* j */ } } - -CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemStorage *storage, double scaleFactor, - int minNeighbors, int flags, CvSize minSize, CvSize maxSize) +void OclCascadeClassifier::detectMultiScale(oclMat &gimg, CV_OUT std::vector& faces, + double scaleFactor, int minNeighbors, int flags, + Size minSize, Size maxSize) +//CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemStorage *storage, double scaleFactor, +// int minNeighbors, int flags, CvSize minSize, CvSize maxSize) { CvHaarClassifierCascade *cascade = oldCascade; const double GROUP_EPS = 0.2; - CvSeq *result_seq = 0; cv::ConcurrentRectVector allCandidates; std::vector rectList; @@ -714,8 +712,8 @@ CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemS if( !CV_IS_HAAR_CLASSIFIER(cascade) ) CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" ); - if( !storage ) - CV_Error( CV_StsNullPtr, "Null storage pointer" ); + //if( !storage ) + // CV_Error( CV_StsNullPtr, "Null storage pointer" ); if( CV_MAT_DEPTH(gimg.type()) != CV_8U ) CV_Error( CV_StsUnsupportedFormat, "Only 8-bit images are supported" ); @@ -729,7 +727,7 @@ CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemS if( !cascade->hid_cascade ) gpuCreateHidHaarClassifierCascade(cascade, &datasize, &totalclassifier); - result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage ); + //result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage ); if( CV_MAT_CN(gimg.type()) > 1 ) { @@ -1028,7 +1026,7 @@ CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemS args.push_back ( std::make_pair(sizeof(cl_mem) , (void *)&pbuffer )); args.push_back ( std::make_pair(sizeof(cl_mem) , (void *)&correctionbuffer )); args.push_back ( std::make_pair(sizeof(cl_int) , (void *)&nodenum )); - + const char * build_options = gcascade->is_stump_based ? "-D STUMP_BASED=1" : "-D STUMP_BASED=0"; openCLExecuteKernel(gsum.clCxt, &haarobjectdetect_scaled2, "gpuRunHaarClassifierCascade_scaled2", globalThreads, localThreads, args, -1, -1, build_options); candidate = (int *)clEnqueueMapBuffer(qu, candidatebuffer, 1, CL_MAP_READ, 0, 4 * sizeof(int) * outputsz, 0, 0, 0, &status); @@ -1062,623 +1060,22 @@ CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemS else rweights.resize(rectList.size(), 0); + faces.clear(); if( findBiggestObject && rectList.size() ) { - CvAvgComp result_comp = {{0, 0, 0, 0}, 0}; - + Rect result_comp(0, 0, 0, 0); for( size_t i = 0; i < rectList.size(); i++ ) { cv::Rect r = rectList[i]; - if( r.area() > cv::Rect(result_comp.rect).area() ) + if( r.area() > result_comp.area() ) { - result_comp.rect = r; - result_comp.neighbors = rweights[i]; + result_comp = r; } } - cvSeqPush( result_seq, &result_comp ); + faces.push_back(result_comp); } else { - for( size_t i = 0; i < rectList.size(); i++ ) - { - CvAvgComp c; - c.rect = rectList[i]; - c.neighbors = rweights[i]; - cvSeqPush( result_seq, &c ); - } - } - - return result_seq; -} - -struct OclBuffers -{ - cl_mem stagebuffer; - cl_mem nodebuffer; - cl_mem candidatebuffer; - cl_mem scaleinfobuffer; - cl_mem pbuffer; - cl_mem correctionbuffer; - cl_mem newnodebuffer; -}; - -struct getRect -{ - Rect operator()(const CvAvgComp &e) const - { - return e.rect; - } -}; - -void cv::ocl::OclCascadeClassifierBuf::detectMultiScale(oclMat &gimg, CV_OUT std::vector& faces, - double scaleFactor, int minNeighbors, int flags, - Size minSize, Size maxSize) -{ - int blocksize = 8; - int grp_per_CU = 12; - size_t localThreads[3] = { blocksize, blocksize, 1 }; - size_t globalThreads[3] = { grp_per_CU * cv::ocl::Context::getContext()->computeUnits() *localThreads[0], - localThreads[1], - 1 }; - int outputsz = 256 * globalThreads[0] / localThreads[0]; - - Init(gimg.rows, gimg.cols, scaleFactor, flags, outputsz, localThreads, minSize, maxSize); - - const double GROUP_EPS = 0.2; - - cv::ConcurrentRectVector allCandidates; - std::vector rectList; - std::vector rweights; - - CvHaarClassifierCascade *cascade = oldCascade; - GpuHidHaarClassifierCascade *gcascade; - GpuHidHaarStageClassifier *stage; - - if( CV_MAT_DEPTH(gimg.type()) != CV_8U ) - CV_Error( CV_StsUnsupportedFormat, "Only 8-bit images are supported" ); - - if( CV_MAT_CN(gimg.type()) > 1 ) - { - oclMat gtemp; - cvtColor( gimg, gtemp, CV_BGR2GRAY ); - gimg = gtemp; - } - - int *candidate; - cl_command_queue qu = reinterpret_cast(Context::getContext()->oclCommandQueue()); - if( (flags & CV_HAAR_SCALE_IMAGE) ) - { - int indexy = 0; - CvSize sz; - - cv::Rect roi, roi2; - cv::Mat imgroi, imgroisq; - cv::ocl::oclMat resizeroi, gimgroi, gimgroisq; - - for( int i = 0; i < m_loopcount; i++ ) - { - sz = sizev[i]; - roi = Rect(0, indexy, sz.width, sz.height); - roi2 = Rect(0, 0, sz.width - 1, sz.height - 1); - resizeroi = gimg1(roi2); - gimgroi = gsum(roi); - gimgroisq = gsqsum(roi); - - cv::ocl::resize(gimg, resizeroi, Size(sz.width - 1, sz.height - 1), 0, 0, INTER_LINEAR); - cv::ocl::integral(resizeroi, gimgroi, gimgroisq); - indexy += sz.height; - } - - gcascade = (GpuHidHaarClassifierCascade *)(cascade->hid_cascade); - stage = (GpuHidHaarStageClassifier *)(gcascade + 1); - - int startstage = 0; - int endstage = gcascade->count; - int startnode = 0; - int pixelstep = gsum.step / 4; - int splitstage = 3; - int splitnode = stage[0].count + stage[1].count + stage[2].count; - cl_int4 p, pq; - p.s[0] = gcascade->p0; - p.s[1] = gcascade->p1; - p.s[2] = gcascade->p2; - p.s[3] = gcascade->p3; - pq.s[0] = gcascade->pq0; - pq.s[1] = gcascade->pq1; - pq.s[2] = gcascade->pq2; - pq.s[3] = gcascade->pq3; - float correction = gcascade->inv_window_area; - - vector > args; - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->stagebuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->scaleinfobuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->nodebuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&gsum.data )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&gsqsum.data )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->candidatebuffer )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&pixelstep )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&m_loopcount )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&startstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&splitstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&endstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&startnode )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&splitnode )); - args.push_back ( make_pair(sizeof(cl_int4) , (void *)&p )); - args.push_back ( make_pair(sizeof(cl_int4) , (void *)&pq )); - args.push_back ( make_pair(sizeof(cl_float) , (void *)&correction )); - - const char * build_options = gcascade->is_stump_based ? "-D STUMP_BASED=1" : "-D STUMP_BASED=0"; - - openCLExecuteKernel(gsum.clCxt, &haarobjectdetect, "gpuRunHaarClassifierCascade", globalThreads, localThreads, args, -1, -1, build_options); - - candidate = (int *)malloc(4 * sizeof(int) * outputsz); - memset(candidate, 0, 4 * sizeof(int) * outputsz); - - openCLReadBuffer( gsum.clCxt, ((OclBuffers *)buffers)->candidatebuffer, candidate, 4 * sizeof(int)*outputsz ); - - for(int i = 0; i < outputsz; i++) - { - if(candidate[4 * i + 2] != 0) - { - allCandidates.push_back(Rect(candidate[4 * i], candidate[4 * i + 1], - candidate[4 * i + 2], candidate[4 * i + 3])); - } - } - free((void *)candidate); - candidate = NULL; - } - else - { - cv::ocl::integral(gimg, gsum, gsqsum); - - gcascade = (GpuHidHaarClassifierCascade *)cascade->hid_cascade; - - int step = gsum.step / 4; - int startnode = 0; - int splitstage = 3; - - int startstage = 0; - int endstage = gcascade->count; - - vector > args; - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->stagebuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->scaleinfobuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->newnodebuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&gsum.data )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&gsqsum.data )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->candidatebuffer )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&gsum.rows )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&gsum.cols )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&step )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&m_loopcount )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&startstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&splitstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&endstage )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&startnode )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->pbuffer )); - args.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->correctionbuffer )); - args.push_back ( make_pair(sizeof(cl_int) , (void *)&m_nodenum )); - - const char * build_options = gcascade->is_stump_based ? "-D STUMP_BASED=1" : "-D STUMP_BASED=0"; - openCLExecuteKernel(gsum.clCxt, &haarobjectdetect_scaled2, "gpuRunHaarClassifierCascade_scaled2", globalThreads, localThreads, args, -1, -1, build_options); - - candidate = (int *)clEnqueueMapBuffer(qu, ((OclBuffers *)buffers)->candidatebuffer, 1, CL_MAP_READ, 0, 4 * sizeof(int) * outputsz, 0, 0, 0, NULL); - - for(int i = 0; i < outputsz; i++) - { - if(candidate[4 * i + 2] != 0) - allCandidates.push_back(Rect(candidate[4 * i], candidate[4 * i + 1], - candidate[4 * i + 2], candidate[4 * i + 3])); - } - clEnqueueUnmapMemObject(qu, ((OclBuffers *)buffers)->candidatebuffer, candidate, 0, 0, 0); - } - rectList.resize(allCandidates.size()); - if(!allCandidates.empty()) - std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin()); - - if( minNeighbors != 0 || findBiggestObject ) - groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS); - else - rweights.resize(rectList.size(), 0); - - GenResult(faces, rectList, rweights); -} - -void cv::ocl::OclCascadeClassifierBuf::Init(const int rows, const int cols, - double scaleFactor, int flags, - const int outputsz, const size_t localThreads[], - CvSize minSize, CvSize maxSize) -{ - if(initialized) - { - return; // we only allow one time initialization - } - CvHaarClassifierCascade *cascade = oldCascade; - - if( !CV_IS_HAAR_CLASSIFIER(cascade) ) - CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" ); - - if( scaleFactor <= 1 ) - CV_Error( CV_StsOutOfRange, "scale factor must be > 1" ); - - if( cols < minSize.width || rows < minSize.height ) - CV_Error(CV_StsError, "Image too small"); - - int datasize=0; - int totalclassifier=0; - - if( !cascade->hid_cascade ) - { - gpuCreateHidHaarClassifierCascade(cascade, &datasize, &totalclassifier); - } - - if( maxSize.height == 0 || maxSize.width == 0 ) - { - maxSize.height = rows; - maxSize.width = cols; - } - - findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0; - if( findBiggestObject ) - flags &= ~(CV_HAAR_SCALE_IMAGE | CV_HAAR_DO_CANNY_PRUNING); - - CreateBaseBufs(datasize, totalclassifier, flags, outputsz); - CreateFactorRelatedBufs(rows, cols, flags, scaleFactor, localThreads, minSize, maxSize); - - m_scaleFactor = scaleFactor; - m_rows = rows; - m_cols = cols; - m_flags = flags; - m_minSize = minSize; - m_maxSize = maxSize; - - // initialize nodes - GpuHidHaarClassifierCascade *gcascade; - GpuHidHaarStageClassifier *stage; - GpuHidHaarClassifier *classifier; - GpuHidHaarTreeNode *node; - cl_command_queue qu = reinterpret_cast(Context::getContext()->oclCommandQueue()); - if( (flags & CV_HAAR_SCALE_IMAGE) ) - { - gcascade = (GpuHidHaarClassifierCascade *)(cascade->hid_cascade); - stage = (GpuHidHaarStageClassifier *)(gcascade + 1); - classifier = (GpuHidHaarClassifier *)(stage + gcascade->count); - node = (GpuHidHaarTreeNode *)(classifier->node); - - gpuSetImagesForHaarClassifierCascade( cascade, 1., gsum.step / 4 ); - - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->stagebuffer, 1, 0, - sizeof(GpuHidHaarStageClassifier) * gcascade->count, - stage, 0, NULL, NULL)); - - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->nodebuffer, 1, 0, - m_nodenum * sizeof(GpuHidHaarTreeNode), - node, 0, NULL, NULL)); - } - else - { - gpuSetHaarClassifierCascade(cascade); - - gcascade = (GpuHidHaarClassifierCascade *)cascade->hid_cascade; - stage = (GpuHidHaarStageClassifier *)(gcascade + 1); - classifier = (GpuHidHaarClassifier *)(stage + gcascade->count); - node = (GpuHidHaarTreeNode *)(classifier->node); - - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->nodebuffer, 1, 0, - m_nodenum * sizeof(GpuHidHaarTreeNode), - node, 0, NULL, NULL)); - - cl_int4 *p = (cl_int4 *)malloc(sizeof(cl_int4) * m_loopcount); - float *correction = (float *)malloc(sizeof(float) * m_loopcount); - double factor; - for(int i = 0; i < m_loopcount; i++) - { - factor = scalev[i]; - int equRect_x = (int)(factor * gcascade->p0 + 0.5); - int equRect_y = (int)(factor * gcascade->p1 + 0.5); - int equRect_w = (int)(factor * gcascade->p3 + 0.5); - int equRect_h = (int)(factor * gcascade->p2 + 0.5); - p[i].s[0] = equRect_x; - p[i].s[1] = equRect_y; - p[i].s[2] = equRect_x + equRect_w; - p[i].s[3] = equRect_y + equRect_h; - correction[i] = 1. / (equRect_w * equRect_h); - int startnodenum = m_nodenum * i; - float factor2 = (float)factor; - - vector > args1; - args1.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->nodebuffer )); - args1.push_back ( make_pair(sizeof(cl_mem) , (void *)&((OclBuffers *)buffers)->newnodebuffer )); - args1.push_back ( make_pair(sizeof(cl_float) , (void *)&factor2 )); - args1.push_back ( make_pair(sizeof(cl_float) , (void *)&correction[i] )); - args1.push_back ( make_pair(sizeof(cl_int) , (void *)&startnodenum )); - - size_t globalThreads2[3] = {m_nodenum, 1, 1}; - - openCLExecuteKernel(Context::getContext(), &haarobjectdetect_scaled2, "gpuscaleclassifier", globalThreads2, NULL/*localThreads2*/, args1, -1, -1); - } - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->stagebuffer, 1, 0, sizeof(GpuHidHaarStageClassifier)*gcascade->count, stage, 0, NULL, NULL)); - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->pbuffer, 1, 0, sizeof(cl_int4)*m_loopcount, p, 0, NULL, NULL)); - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->correctionbuffer, 1, 0, sizeof(cl_float)*m_loopcount, correction, 0, NULL, NULL)); - - free(p); - free(correction); - } - initialized = true; -} - -void cv::ocl::OclCascadeClassifierBuf::CreateBaseBufs(const int datasize, const int totalclassifier, - const int flags, const int outputsz) -{ - if (!initialized) - { - buffers = malloc(sizeof(OclBuffers)); - - size_t tempSize = - sizeof(GpuHidHaarStageClassifier) * ((GpuHidHaarClassifierCascade *)oldCascade->hid_cascade)->count; - m_nodenum = (datasize - sizeof(GpuHidHaarClassifierCascade) - tempSize - sizeof(GpuHidHaarClassifier) * totalclassifier) - / sizeof(GpuHidHaarTreeNode); - - ((OclBuffers *)buffers)->stagebuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_ONLY, tempSize); - ((OclBuffers *)buffers)->nodebuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_ONLY, m_nodenum * sizeof(GpuHidHaarTreeNode)); - } - - if (initialized - && ((m_flags & CV_HAAR_SCALE_IMAGE) ^ (flags & CV_HAAR_SCALE_IMAGE))) - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->candidatebuffer)); - } - - if (flags & CV_HAAR_SCALE_IMAGE) - { - ((OclBuffers *)buffers)->candidatebuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), - CL_MEM_WRITE_ONLY, - 4 * sizeof(int) * outputsz); - } - else - { - ((OclBuffers *)buffers)->candidatebuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), - CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, - 4 * sizeof(int) * outputsz); + faces = rectList; } } - -void cv::ocl::OclCascadeClassifierBuf::CreateFactorRelatedBufs( - const int rows, const int cols, const int flags, - const double scaleFactor, const size_t localThreads[], - CvSize minSize, CvSize maxSize) -{ - if (initialized) - { - if ((m_flags & CV_HAAR_SCALE_IMAGE) && !(flags & CV_HAAR_SCALE_IMAGE)) - { - gimg1.release(); - gsum.release(); - gsqsum.release(); - } - else if (!(m_flags & CV_HAAR_SCALE_IMAGE) && (flags & CV_HAAR_SCALE_IMAGE)) - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->newnodebuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->correctionbuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->pbuffer)); - } - else if ((m_flags & CV_HAAR_SCALE_IMAGE) && (flags & CV_HAAR_SCALE_IMAGE)) - { - if (fabs(m_scaleFactor - scaleFactor) < 1e-6 - && (rows == m_rows && cols == m_cols) - && (minSize.width == m_minSize.width) - && (minSize.height == m_minSize.height) - && (maxSize.width == m_maxSize.width) - && (maxSize.height == m_maxSize.height)) - { - return; - } - } - else - { - if (fabs(m_scaleFactor - scaleFactor) < 1e-6 - && (rows == m_rows && cols == m_cols) - && (minSize.width == m_minSize.width) - && (minSize.height == m_minSize.height) - && (maxSize.width == m_maxSize.width) - && (maxSize.height == m_maxSize.height)) - { - return; - } - else - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->newnodebuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->correctionbuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->pbuffer)); - } - } - } - - int loopcount; - int indexy = 0; - int totalheight = 0; - double factor; - Rect roi; - CvSize sz; - CvSize winSize0 = oldCascade->orig_window_size; - detect_piramid_info *scaleinfo; - cl_command_queue qu = reinterpret_cast(Context::getContext()->oclCommandQueue()); - if (flags & CV_HAAR_SCALE_IMAGE) - { - for(factor = 1.f;; factor *= scaleFactor) - { - CvSize winSize = { cvRound(winSize0.width * factor), cvRound(winSize0.height * factor) }; - sz.width = cvRound( cols / factor ) + 1; - sz.height = cvRound( rows / factor ) + 1; - CvSize sz1 = { sz.width - winSize0.width - 1, sz.height - winSize0.height - 1 }; - - if( sz1.width <= 0 || sz1.height <= 0 ) - break; - if( winSize.width > maxSize.width || winSize.height > maxSize.height ) - break; - if( winSize.width < minSize.width || winSize.height < minSize.height ) - continue; - - totalheight += sz.height; - sizev.push_back(sz); - scalev.push_back(static_cast(factor)); - } - - loopcount = sizev.size(); - gimg1.create(rows, cols, CV_8UC1); - gsum.create(totalheight + 4, cols + 1, CV_32SC1); - gsqsum.create(totalheight + 4, cols + 1, CV_32FC1); - - scaleinfo = (detect_piramid_info *)malloc(sizeof(detect_piramid_info) * loopcount); - for( int i = 0; i < loopcount; i++ ) - { - sz = sizev[i]; - roi = Rect(0, indexy, sz.width, sz.height); - int width = sz.width - 1 - oldCascade->orig_window_size.width; - int height = sz.height - 1 - oldCascade->orig_window_size.height; - int grpnumperline = (width + localThreads[0] - 1) / localThreads[0]; - int totalgrp = ((height + localThreads[1] - 1) / localThreads[1]) * grpnumperline; - - ((detect_piramid_info *)scaleinfo)[i].width_height = (width << 16) | height; - ((detect_piramid_info *)scaleinfo)[i].grpnumperline_totalgrp = (grpnumperline << 16) | totalgrp; - ((detect_piramid_info *)scaleinfo)[i].imgoff = gsum(roi).offset >> 2; - ((detect_piramid_info *)scaleinfo)[i].factor = scalev[i]; - - indexy += sz.height; - } - } - else - { - for(factor = 1; - cvRound(factor * winSize0.width) < cols - 10 && cvRound(factor * winSize0.height) < rows - 10; - factor *= scaleFactor) - { - CvSize winSize = { cvRound( winSize0.width * factor ), cvRound( winSize0.height * factor ) }; - if( winSize.width < minSize.width || winSize.height < minSize.height ) - { - continue; - } - sizev.push_back(winSize); - scalev.push_back(factor); - } - - loopcount = scalev.size(); - if(loopcount == 0) - { - loopcount = 1; - sizev.push_back(minSize); - scalev.push_back( min(cvRound(minSize.width / winSize0.width), cvRound(minSize.height / winSize0.height)) ); - } - - ((OclBuffers *)buffers)->pbuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_ONLY, - sizeof(cl_int4) * loopcount); - ((OclBuffers *)buffers)->correctionbuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_ONLY, - sizeof(cl_float) * loopcount); - ((OclBuffers *)buffers)->newnodebuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_WRITE, - loopcount * m_nodenum * sizeof(GpuHidHaarTreeNode)); - - scaleinfo = (detect_piramid_info *)malloc(sizeof(detect_piramid_info) * loopcount); - for( int i = 0; i < loopcount; i++ ) - { - sz = sizev[i]; - factor = scalev[i]; - int ystep = cvRound(std::max(2., factor)); - int width = (cols - 1 - sz.width + ystep - 1) / ystep; - int height = (rows - 1 - sz.height + ystep - 1) / ystep; - int grpnumperline = (width + localThreads[0] - 1) / localThreads[0]; - int totalgrp = ((height + localThreads[1] - 1) / localThreads[1]) * grpnumperline; - - ((detect_piramid_info *)scaleinfo)[i].width_height = (width << 16) | height; - ((detect_piramid_info *)scaleinfo)[i].grpnumperline_totalgrp = (grpnumperline << 16) | totalgrp; - ((detect_piramid_info *)scaleinfo)[i].imgoff = 0; - ((detect_piramid_info *)scaleinfo)[i].factor = factor; - } - } - - if (loopcount != m_loopcount) - { - if (initialized) - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->scaleinfobuffer)); - } - ((OclBuffers *)buffers)->scaleinfobuffer = openCLCreateBuffer(cv::ocl::Context::getContext(), CL_MEM_READ_ONLY, sizeof(detect_piramid_info) * loopcount); - } - - openCLSafeCall(clEnqueueWriteBuffer(qu, ((OclBuffers *)buffers)->scaleinfobuffer, 1, 0, - sizeof(detect_piramid_info)*loopcount, - scaleinfo, 0, NULL, NULL)); - free(scaleinfo); - - m_loopcount = loopcount; -} - -void cv::ocl::OclCascadeClassifierBuf::GenResult(CV_OUT std::vector& faces, - const std::vector &rectList, - const std::vector &rweights) -{ - MemStorage tempStorage(cvCreateMemStorage(0)); - CvSeq *result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), tempStorage ); - - if( findBiggestObject && rectList.size() ) - { - CvAvgComp result_comp = {CvRect(), 0}; - - for( size_t i = 0; i < rectList.size(); i++ ) - { - cv::Rect r = rectList[i]; - if( r.area() > cv::Rect(result_comp.rect).area() ) - { - result_comp.rect = r; - result_comp.neighbors = rweights[i]; - } - } - cvSeqPush( result_seq, &result_comp ); - } - else - { - for( size_t i = 0; i < rectList.size(); i++ ) - { - CvAvgComp c; - c.rect = rectList[i]; - c.neighbors = rweights[i]; - cvSeqPush( result_seq, &c ); - } - } - - vector vecAvgComp; - Seq(result_seq).copyTo(vecAvgComp); - faces.resize(vecAvgComp.size()); - std::transform(vecAvgComp.begin(), vecAvgComp.end(), faces.begin(), getRect()); -} - -void cv::ocl::OclCascadeClassifierBuf::release() -{ - if(initialized) - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->stagebuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->scaleinfobuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->nodebuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->candidatebuffer)); - - if( (m_flags & CV_HAAR_SCALE_IMAGE) ) - { - cvFree(&oldCascade->hid_cascade); - } - else - { - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->newnodebuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->correctionbuffer)); - openCLSafeCall(clReleaseMemObject(((OclBuffers *)buffers)->pbuffer)); - } - - free(buffers); - buffers = NULL; - initialized = false; - } -} - -#ifndef _MAX_PATH -#define _MAX_PATH 1024 -#endif - -#endif diff --git a/modules/ocl/src/precomp.hpp b/modules/ocl/src/precomp.hpp index 3b75f303d4..2704428895 100644 --- a/modules/ocl/src/precomp.hpp +++ b/modules/ocl/src/precomp.hpp @@ -64,7 +64,7 @@ #undef OPENCV_NOSTL #include "opencv2/imgproc.hpp" -#include "opencv2/objdetect.hpp" +#include "opencv2/objdetect/objdetect_c.h" #include "opencv2/ocl.hpp" #include "opencv2/core/utility.hpp" diff --git a/modules/ocl/test/test_objdetect.cpp b/modules/ocl/test/test_objdetect.cpp index 91ec165d6b..d68228b54f 100644 --- a/modules/ocl/test/test_objdetect.cpp +++ b/modules/ocl/test/test_objdetect.cpp @@ -44,9 +44,7 @@ //M*/ #include "precomp.hpp" - #include "opencv2/objdetect.hpp" -#include "opencv2/objdetect/objdetect_c.h" using namespace std; using namespace cv; @@ -188,18 +186,11 @@ INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, HOG, testing::Combine( testing::Values(Size(64, 128), Size(48, 96)), testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); -#if 0 + ///////////////////////////// Haar ////////////////////////////// IMPLEMENT_PARAM_CLASS(CascadeName, std::string); CascadeName cascade_frontalface_alt(std::string("haarcascade_frontalface_alt.xml")); CascadeName cascade_frontalface_alt2(std::string("haarcascade_frontalface_alt2.xml")); -struct getRect -{ - Rect operator ()(const CvAvgComp &e) const - { - return e.rect; - } -}; PARAM_TEST_CASE(Haar, int, CascadeName) { @@ -234,49 +225,18 @@ PARAM_TEST_CASE(Haar, int, CascadeName) TEST_P(Haar, FaceDetect) { - MemStorage storage(cvCreateMemStorage(0)); - CvSeq *_objects; - _objects = cascade.oclHaarDetectObjects(d_img, storage, 1.1, 3, - flags, Size(30, 30), Size(0, 0)); - vector vecAvgComp; - Seq(_objects).copyTo(vecAvgComp); - oclfaces.resize(vecAvgComp.size()); - std::transform(vecAvgComp.begin(), vecAvgComp.end(), oclfaces.begin(), getRect()); + cascade.detectMultiScale(d_img, oclfaces, 1.1, 3, + flags, Size(30, 30)); - cpucascade.detectMultiScale(img, faces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0)); - - EXPECT_LT(checkRectSimilarity(img.size(), faces, oclfaces), 1.0); -} - -TEST_P(Haar, FaceDetectUseBuf) -{ - ocl::OclCascadeClassifierBuf cascadebuf; - if(!cascadebuf.load(cascadeName)) - { - std::cout << "ERROR: Could not load classifier cascade for FaceDetectUseBuf!" << std::endl; - return; - } - cascadebuf.detectMultiScale(d_img, oclfaces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0)); - cpucascade.detectMultiScale(img, faces, 1.1, 3, - flags, - Size(30, 30), Size(0, 0)); - - // intentionally run ocl facedetect again and check if it still works after the first run - cascadebuf.detectMultiScale(d_img, oclfaces, 1.1, 3, - flags, - Size(30, 30)); - cascadebuf.release(); + cpucascade.detectMultiScale(img, faces, 1.1, 3, + flags, Size(30, 30)); EXPECT_LT(checkRectSimilarity(img.size(), faces, oclfaces), 1.0); } INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, Haar, - Combine(Values(CV_HAAR_SCALE_IMAGE, 0), - Values(cascade_frontalface_alt/*, cascade_frontalface_alt2*/))); -#endif + Combine(Values((int)CASCADE_SCALE_IMAGE, 0), + Values(cascade_frontalface_alt, cascade_frontalface_alt2))); + #endif //HAVE_OPENCL diff --git a/samples/ocl/facedetect.cpp b/samples/ocl/facedetect.cpp index 34aeeeaf52..059134e165 100644 --- a/samples/ocl/facedetect.cpp +++ b/samples/ocl/facedetect.cpp @@ -8,9 +8,6 @@ #include #include -int main( int, const char** ) { return 0; } - -#if 0 using namespace std; using namespace cv; @@ -46,7 +43,7 @@ static double getTime() } void detect( Mat& img, vector& faces, - ocl::OclCascadeClassifierBuf& cascade, + ocl::OclCascadeClassifier& cascade, double scale, bool calTime); @@ -66,20 +63,19 @@ double checkRectSimilarity(Size sz, vector& cpu_rst, vector& gpu_rst int main( int argc, const char** argv ) { const char* keys = - "{ h | help | false | print help message }" - "{ i | input | | specify input image }" - "{ t | template | haarcascade_frontalface_alt.xml |" + "{ h help | false | print help message }" + "{ i input | | specify input image }" + "{ t template | haarcascade_frontalface_alt.xml |" " specify template file path }" - "{ c | scale | 1.0 | scale image }" - "{ s | use_cpu | false | use cpu or gpu to process the image }" - "{ o | output | facedetect_output.jpg |" + "{ c scale | 1.0 | scale image }" + "{ s use_cpu | false | use cpu or gpu to process the image }" + "{ o output | facedetect_output.jpg |" " specify output image save path(only works when input is images) }"; CommandLineParser cmd(argc, argv, keys); if (cmd.get("help")) { cout << "Avaible options:" << endl; - cmd.printParams(); return 0; } CvCapture* capture = 0; @@ -90,7 +86,7 @@ int main( int argc, const char** argv ) outputName = cmd.get("o"); string cascadeName = cmd.get("t"); double scale = cmd.get("c"); - ocl::OclCascadeClassifierBuf cascade; + ocl::OclCascadeClassifier cascade; CascadeClassifier cpu_cascade; if( !cascade.load( cascadeName ) || !cpu_cascade.load(cascadeName) ) @@ -211,7 +207,7 @@ _cleanup_: } void detect( Mat& img, vector& faces, - ocl::OclCascadeClassifierBuf& cascade, + ocl::OclCascadeClassifier& cascade, double scale, bool calTime) { ocl::oclMat image(img); @@ -223,7 +219,7 @@ void detect( Mat& img, vector& faces, cascade.detectMultiScale( smallImg, faces, 1.1, 3, 0 - |CV_HAAR_SCALE_IMAGE + |CASCADE_SCALE_IMAGE , Size(30,30), Size(0, 0) ); if(calTime) workEnd(); } @@ -234,11 +230,11 @@ void detectCPU( Mat& img, vector& faces, { if(calTime) workBegin(); Mat cpu_gray, cpu_smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); - cvtColor(img, cpu_gray, CV_BGR2GRAY); + cvtColor(img, cpu_gray, COLOR_BGR2GRAY); resize(cpu_gray, cpu_smallImg, cpu_smallImg.size(), 0, 0, INTER_LINEAR); equalizeHist(cpu_smallImg, cpu_smallImg); cascade.detectMultiScale(cpu_smallImg, faces, 1.1, - 3, 0 | CV_HAAR_SCALE_IMAGE, + 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30), Size(0, 0)); if(calTime) workEnd(); } @@ -311,5 +307,4 @@ double checkRectSimilarity(Size sz, vector& ob1, vector& ob2) final_test_result = -1; } return final_test_result; -} -#endif +} \ No newline at end of file From 52b250f4665160022b80eff604a4b2f20bdbebe3 Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 25 Jul 2013 14:30:20 +0300 Subject: [PATCH 17/22] Minor fixes Fixing failed build. --- modules/optim/src/lpsolver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 0690387ac7..45999b0119 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -91,7 +91,6 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ z.create(c.cols,1,CV_64FC1); MatIterator_ it=z.begin(); for(int i=1;i<=c.cols;i++,it++){ - std::vector::iterator pos=B.begin(); if(indexToRow[i] Date: Fri, 26 Jul 2013 14:52:56 +0400 Subject: [PATCH 18/22] Replace "const InputArray" with "InputArray". InputArray is a reference, and references are always constant anyway. Making it const even causes a GCC warning. --- modules/imgproc/include/opencv2/imgproc.hpp | 6 +++--- modules/imgproc/src/lsd.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index dd849ef4c2..bf8f795ac4 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -859,7 +859,7 @@ public: * * 1 corresponds to 0.1 mean false alarms * This vector will be calculated _only_ when the objects type is REFINE_ADV */ - virtual void detect(const InputArray _image, OutputArray _lines, + virtual void detect(InputArray _image, OutputArray _lines, OutputArray width = noArray(), OutputArray prec = noArray(), OutputArray nfa = noArray()) = 0; @@ -870,7 +870,7 @@ public: * Should have the size of the image, where the lines were found * @param lines The lines that need to be drawn */ - virtual void drawSegments(InputOutputArray image, const InputArray lines) = 0; + virtual void drawSegments(InputOutputArray image, InputArray lines) = 0; /** * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. @@ -881,7 +881,7 @@ public: * @param lines2 The second lines that need to be drawn. Color - Red. * @return The number of mismatching pixels between lines1 and lines2. */ - virtual int compareSegments(const Size& size, const InputArray lines1, const InputArray lines2, Mat* image = 0) = 0; + virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, Mat* image = 0) = 0; virtual ~LineSegmentDetector() {}; }; diff --git a/modules/imgproc/src/lsd.cpp b/modules/imgproc/src/lsd.cpp index b4f228a382..58d226f0c4 100644 --- a/modules/imgproc/src/lsd.cpp +++ b/modules/imgproc/src/lsd.cpp @@ -205,7 +205,7 @@ public: * * 1 corresponds to 0.1 mean false alarms * This vector will be calculated _only_ when the objects type is REFINE_ADV */ - void detect(const InputArray _image, OutputArray _lines, + void detect(InputArray _image, OutputArray _lines, OutputArray width = noArray(), OutputArray prec = noArray(), OutputArray nfa = noArray()); @@ -216,7 +216,7 @@ public: * Should have the size of the image, where the lines were found * @param lines The lines that need to be drawn */ - void drawSegments(InputOutputArray image, const InputArray lines); + void drawSegments(InputOutputArray image, InputArray lines); /** * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. @@ -227,7 +227,7 @@ public: * @param lines2 The second lines that need to be drawn. Color - Red. * @return The number of mismatching pixels between lines1 and lines2. */ - int compareSegments(const Size& size, const InputArray lines1, const InputArray lines2, Mat* image = 0); + int compareSegments(const Size& size, InputArray lines1, InputArray lines2, Mat* image = 0); private: Mat image; From 25b9ac18e61628b784cfb0851771654ef56f0f4b Mon Sep 17 00:00:00 2001 From: Alexander Mordvintsev Date: Fri, 26 Jul 2013 17:58:39 +0400 Subject: [PATCH 19/22] fixed Bug #3143 - flann 'not implemented' error --- modules/python/src2/cv2.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index c593676415..2de187ceea 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -510,13 +510,6 @@ PyObject* pyopencv_from(const cvflann_flann_distance_t& value) return PyInt_FromLong(int(value)); } -template<> -bool pyopencv_to(PyObject*, cv::flann::SearchParams &, const char *) -{ - CV_Assert(!"not implemented"); - return false; -} - template<> bool pyopencv_to(PyObject* obj, int& value, const char* name) { @@ -1055,6 +1048,12 @@ bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const char *name) return ok; } +template<> +bool pyopencv_to(PyObject* obj, cv::flann::SearchParams & value, const char * name) +{ + return pyopencv_to(obj, value, name); +} + template bool pyopencv_to(PyObject *o, Ptr& p, const char *name) { From 7dc147c1f2faa7f3dbe7f373bbd6d46d40b820e9 Mon Sep 17 00:00:00 2001 From: Shervin Emami Date: Fri, 26 Jul 2013 19:13:25 -0700 Subject: [PATCH 20/22] Changed cornerHarris description to say it finds corners, not edges --- modules/imgproc/doc/feature_detection.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/imgproc/doc/feature_detection.rst b/modules/imgproc/doc/feature_detection.rst index c88eaef650..700105ad1a 100644 --- a/modules/imgproc/doc/feature_detection.rst +++ b/modules/imgproc/doc/feature_detection.rst @@ -85,7 +85,7 @@ The output of the function can be used for robust edge or corner detection. cornerHarris ------------ -Harris edge detector. +Harris corner detector. .. ocv:function:: void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT ) @@ -105,7 +105,7 @@ Harris edge detector. :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` . -The function runs the Harris edge detector on the image. Similarly to +The function runs the Harris corner detector on the image. Similarly to :ocv:func:`cornerMinEigenVal` and :ocv:func:`cornerEigenValsAndVecs` , for each pixel :math:`(x, y)` it calculates a From 1b10860f36378ff24568f11f242acabbcefefefe Mon Sep 17 00:00:00 2001 From: berak Date: Mon, 29 Jul 2013 12:16:37 +0200 Subject: [PATCH 21/22] added add_definitions(-DCVAPI_EXPORTS) to cmakelists.txt --- modules/python/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/python/CMakeLists.txt b/modules/python/CMakeLists.txt index 0b4c59d636..877b454174 100644 --- a/modules/python/CMakeLists.txt +++ b/modules/python/CMakeLists.txt @@ -81,6 +81,10 @@ if(ENABLE_SOLUTION_FOLDERS) set_target_properties(${the_module} PROPERTIES FOLDER "bindings") endif() +if(MSVC) + add_definitions(-DCVAPI_EXPORTS) +endif() + if(CMAKE_COMPILER_IS_GNUCXX AND NOT ENABLE_NOISY_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function") endif() From 3013ad6624cdf68046e58aa7679e8cfdb7333e7b Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Tue, 30 Jul 2013 04:14:36 +0300 Subject: [PATCH 22/22] Minor fixes Request to comments on pull request for simplex method. In particular *) while(1) is replaced with for(;;) *) if(true){...} constructions in tests are replaced with #if 1 ... #endif --- modules/optim/src/lpsolver.cpp | 2 +- modules/optim/test/test_lpsolver.cpp | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 45999b0119..72db13a0c4 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -208,7 +208,7 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector< static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow){ int count=0; - while(1){ + for(;;){ dprintf(("iteration #%d\n",count)); count++; diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp index 5a7f4c484e..f39c7eb371 100644 --- a/modules/optim/test/test_lpsolver.cpp +++ b/modules/optim/test/test_lpsolver.cpp @@ -4,7 +4,7 @@ TEST(Optim_LpSolver, regression_basic){ cv::Mat A,B,z,etalon_z; - if(true){ +#if 1 //cormen's example #1 A=(cv::Mat_(3,1)<<3,1,2); B=(cv::Mat_(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36); @@ -13,9 +13,9 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here z goes\n"<(3,1)<<8,4,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); - } +#endif - if(true){ +#if 1 //cormen's example #2 A=(cv::Mat_(1,2)<<18,12.5); B=(cv::Mat_(3,3)<<1,1,20,1,0,20,0,1,16); @@ -24,9 +24,9 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here z goes\n"<(2,1)<<20,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); - } +#endif - if(true){ +#if 1 //cormen's example #3 A=(cv::Mat_(1,2)<<5,-3); B=(cv::Mat_(2,3)<<1,-1,1,2,1,2); @@ -35,13 +35,13 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here z goes\n"<(2,1)<<1,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); - } +#endif } TEST(Optim_LpSolver, regression_init_unfeasible){ cv::Mat A,B,z,etalon_z; - if(true){ +#if 1 //cormen's example #4 - unfeasible A=(cv::Mat_(1,3)<<-1,-1,-1); B=(cv::Mat_(2,4)<<-2,-7.5,-3,-10000,-20,-5,-10,-30000); @@ -50,26 +50,26 @@ TEST(Optim_LpSolver, regression_init_unfeasible){ std::cout<<"here z goes\n"<(3,1)<<1250,1000,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); - } +#endif } TEST(Optim_LpSolver, regression_absolutely_unfeasible){ cv::Mat A,B,z,etalon_z; - if(true){ +#if 1 //trivial absolutely unfeasible example A=(cv::Mat_(1,1)<<1); B=(cv::Mat_(2,2)<<1,-1); std::cout<<"here A goes\n"<(2,1)<<1,1); B=(cv::Mat_(1,3)<<1,1,1); @@ -80,13 +80,13 @@ TEST(Optim_LpSolver, regression_multiple_solutions){ std::cout<<"here z goes\n"<(4,1)<<10,-57,-9,-24); B=(cv::Mat_(3,5)<<0.5,-5.5,-2.5,9,0,0.5,-1.5,-0.5,1,0,1,0,0,0,1); @@ -97,5 +97,5 @@ TEST(Optim_LpSolver, regression_cycling){ std::cout<<"here z goes\n"<