Move createsamples application from 2.4 version
authorvbystricky <vbystricky@github.com>
Mon, 8 Dec 2014 13:53:14 +0000 (17:53 +0400)
committervbystricky <vbystricky@github.com>
Wed, 10 Dec 2014 08:17:58 +0000 (12:17 +0400)
apps/CMakeLists.txt
apps/createsamples/CMakeLists.txt [new file with mode: 0644]
apps/createsamples/createsamples.cpp [new file with mode: 0644]
apps/createsamples/utility.cpp [new file with mode: 0644]
apps/createsamples/utility.hpp [new file with mode: 0644]

index 1814efb..e9783de 100644 (file)
@@ -2,3 +2,4 @@ add_definitions(-D__OPENCV_BUILD=1)
 link_libraries(${OPENCV_LINKER_LIBS})
 
 add_subdirectory(traincascade)
+add_subdirectory(createsamples)
diff --git a/apps/createsamples/CMakeLists.txt b/apps/createsamples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..591a0b8
--- /dev/null
@@ -0,0 +1,39 @@
+set(OPENCV_CREATESAMPLES_DEPS opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d opencv_videoio)
+ocv_check_dependencies(${OPENCV_CREATESAMPLES_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+  return()
+endif()
+
+project(createsamples)
+set(the_target opencv_createsamples)
+
+ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
+ocv_target_include_modules(${the_target} ${OPENCV_CREATESAMPLES_DEPS})
+
+file(GLOB SRCS *.cpp)
+file(GLOB HDRS *.h*)
+
+set(createsamples_files ${SRCS} ${HDRS})
+
+ocv_add_executable(${the_target} ${createsamples_files})
+ocv_target_link_libraries(${the_target} ${OPENCV_CREATESAMPLES_DEPS})
+
+set_target_properties(${the_target} PROPERTIES
+                      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
+                      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+                      INSTALL_NAME_DIR lib
+                      OUTPUT_NAME "opencv_createsamples")
+
+if(ENABLE_SOLUTION_FOLDERS)
+  set_target_properties(${the_target} PROPERTIES FOLDER "applications")
+endif()
+
+if(INSTALL_CREATE_DISTRIB)
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
+  endif()
+else()
+  install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
+endif()
diff --git a/apps/createsamples/createsamples.cpp b/apps/createsamples/createsamples.cpp
new file mode 100644 (file)
index 0000000..9f05e41
--- /dev/null
@@ -0,0 +1,245 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/*
+ * createsamples.cpp
+ *
+ * Create test/training samples
+ */
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <ctime>
+
+using namespace std;
+
+#include "utility.hpp"
+
+int main( int argc, char* argv[] )
+{
+    int i = 0;
+    char* nullname   = (char*)"(NULL)";
+    char* vecname    = NULL; /* .vec file name */
+    char* infoname   = NULL; /* file name with marked up image descriptions */
+    char* imagename  = NULL; /* single sample image */
+    char* bgfilename = NULL; /* background */
+    int num = 1000;
+    int bgcolor = 0;
+    int bgthreshold = 80;
+    int invert = 0;
+    int maxintensitydev = 40;
+    double maxxangle = 1.1;
+    double maxyangle = 1.1;
+    double maxzangle = 0.5;
+    int showsamples = 0;
+    /* the samples are adjusted to this scale in the sample preview window */
+    double scale = 4.0;
+    int width  = 24;
+    int height = 24;
+
+    srand((unsigned int)time(0));
+
+    if( argc == 1 )
+    {
+        printf( "Usage: %s\n  [-info <collection_file_name>]\n"
+                "  [-img <image_file_name>]\n"
+                "  [-vec <vec_file_name>]\n"
+                "  [-bg <background_file_name>]\n  [-num <number_of_samples = %d>]\n"
+                "  [-bgcolor <background_color = %d>]\n"
+                "  [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"
+                "  [-maxidev <max_intensity_deviation = %d>]\n"
+                "  [-maxxangle <max_x_rotation_angle = %f>]\n"
+                "  [-maxyangle <max_y_rotation_angle = %f>]\n"
+                "  [-maxzangle <max_z_rotation_angle = %f>]\n"
+                "  [-show [<scale = %f>]]\n"
+                "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n",
+                argv[0], num, bgcolor, bgthreshold, maxintensitydev,
+                maxxangle, maxyangle, maxzangle, scale, width, height );
+
+        return 0;
+    }
+
+    for( i = 1; i < argc; ++i )
+    {
+        if( !strcmp( argv[i], "-info" ) )
+        {
+            infoname = argv[++i];
+        }
+        else if( !strcmp( argv[i], "-img" ) )
+        {
+            imagename = argv[++i];
+        }
+        else if( !strcmp( argv[i], "-vec" ) )
+        {
+            vecname = argv[++i];
+        }
+        else if( !strcmp( argv[i], "-bg" ) )
+        {
+            bgfilename = argv[++i];
+        }
+        else if( !strcmp( argv[i], "-num" ) )
+        {
+            num = atoi( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-bgcolor" ) )
+        {
+            bgcolor = atoi( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-bgthresh" ) )
+        {
+            bgthreshold = atoi( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-inv" ) )
+        {
+            invert = 1;
+        }
+        else if( !strcmp( argv[i], "-randinv" ) )
+        {
+            invert = CV_RANDOM_INVERT;
+        }
+        else if( !strcmp( argv[i], "-maxidev" ) )
+        {
+            maxintensitydev = atoi( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-maxxangle" ) )
+        {
+            maxxangle = atof( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-maxyangle" ) )
+        {
+            maxyangle = atof( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-maxzangle" ) )
+        {
+            maxzangle = atof( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-show" ) )
+        {
+            showsamples = 1;
+            if( i+1 < argc && strlen( argv[i+1] ) > 0 && argv[i+1][0] != '-' )
+            {
+                double d;
+                d = strtod( argv[i+1], 0 );
+                if( d != -HUGE_VAL && d != HUGE_VAL && d > 0 ) scale = d;
+                ++i;
+            }
+        }
+        else if( !strcmp( argv[i], "-w" ) )
+        {
+            width = atoi( argv[++i] );
+        }
+        else if( !strcmp( argv[i], "-h" ) )
+        {
+            height = atoi( argv[++i] );
+        }
+    }
+
+    printf( "Info file name: %s\n", ((infoname == NULL) ?   nullname : infoname ) );
+    printf( "Img file name: %s\n",  ((imagename == NULL) ?  nullname : imagename ) );
+    printf( "Vec file name: %s\n",  ((vecname == NULL) ?    nullname : vecname ) );
+    printf( "BG  file name: %s\n",  ((bgfilename == NULL) ? nullname : bgfilename ) );
+    printf( "Num: %d\n", num );
+    printf( "BG color: %d\n", bgcolor );
+    printf( "BG threshold: %d\n", bgthreshold );
+    printf( "Invert: %s\n", (invert == CV_RANDOM_INVERT) ? "RANDOM"
+                                : ( (invert) ? "TRUE" : "FALSE" ) );
+    printf( "Max intensity deviation: %d\n", maxintensitydev );
+    printf( "Max x angle: %g\n", maxxangle );
+    printf( "Max y angle: %g\n", maxyangle );
+    printf( "Max z angle: %g\n", maxzangle );
+    printf( "Show samples: %s\n", (showsamples) ? "TRUE" : "FALSE" );
+    if( showsamples )
+    {
+        printf( "Scale: %g\n", scale );
+    }
+    printf( "Width: %d\n", width );
+    printf( "Height: %d\n", height );
+
+    /* determine action */
+    if( imagename && vecname )
+    {
+        printf( "Create training samples from single image applying distortions...\n" );
+
+        cvCreateTrainingSamples( vecname, imagename, bgcolor, bgthreshold, bgfilename,
+                                 num, invert, maxintensitydev,
+                                 maxxangle, maxyangle, maxzangle,
+                                 showsamples, width, height );
+
+        printf( "Done\n" );
+    }
+    else if( imagename && bgfilename && infoname )
+    {
+        printf( "Create test samples from single image applying distortions...\n" );
+
+        cvCreateTestSamples( infoname, imagename, bgcolor, bgthreshold, bgfilename, num,
+            invert, maxintensitydev,
+            maxxangle, maxyangle, maxzangle, showsamples, width, height );
+
+        printf( "Done\n" );
+    }
+    else if( infoname && vecname )
+    {
+        int total;
+
+        printf( "Create training samples from images collection...\n" );
+
+        total = cvCreateTrainingSamplesFromInfo( infoname, vecname, num, showsamples,
+                                                 width, height );
+
+        printf( "Done. Created %d samples\n", total );
+    }
+    else if( vecname )
+    {
+        printf( "View samples from vec file (press ESC to exit)...\n" );
+
+        cvShowVecSamples( vecname, width, height, scale );
+
+        printf( "Done\n" );
+    }
+    else
+    {
+        printf( "Nothing to do\n" );
+    }
+
+    return 0;
+}
diff --git a/apps/createsamples/utility.cpp b/apps/createsamples/utility.cpp
new file mode 100644 (file)
index 0000000..b5834f3
--- /dev/null
@@ -0,0 +1,1681 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including 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 <cstring>
+#include <ctime>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif /* _WIN32 */
+
+#include "utility.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/core/core_c.h"
+#include "opencv2/imgcodecs/imgcodecs_c.h"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/highgui/highgui_c.h"
+#include "opencv2/calib3d/calib3d_c.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif /* PATH_MAX */
+
+#define __BEGIN__ __CV_BEGIN__
+#define __END__  __CV_END__
+#define EXIT __CV_EXIT__
+
+static int icvMkDir( const char* filename )
+{
+    char path[PATH_MAX];
+    char* p;
+    int pos;
+
+#ifdef _WIN32
+    struct _stat st;
+#else /* _WIN32 */
+    struct stat st;
+    mode_t mode;
+
+    mode = 0755;
+#endif /* _WIN32 */
+
+    strcpy( path, filename );
+
+    p = path;
+    for( ; ; )
+    {
+        pos = (int)strcspn( p, "/\\" );
+
+        if( pos == (int) strlen( p ) ) break;
+        if( pos != 0 )
+        {
+            p[pos] = '\0';
+
+#ifdef _WIN32
+            if( p[pos-1] != ':' )
+            {
+                if( _stat( path, &st ) != 0 )
+                {
+                    if( _mkdir( path ) != 0 ) return 0;
+                }
+            }
+#else /* _WIN32 */
+            if( stat( path, &st ) != 0 )
+            {
+                if( mkdir( path, mode ) != 0 ) return 0;
+            }
+#endif /* _WIN32 */
+        }
+
+        p[pos] = '/';
+
+        p += pos + 1;
+    }
+
+    return 1;
+}
+
+static void icvWriteVecHeader( FILE* file, int count, int width, int height )
+{
+    int vecsize;
+    short tmp;
+
+    /* number of samples */
+    fwrite( &count, sizeof( count ), 1, file );
+    /* vector size */
+    vecsize = width * height;
+    fwrite( &vecsize, sizeof( vecsize ), 1, file );
+    /* min/max values */
+    tmp = 0;
+    fwrite( &tmp, sizeof( tmp ), 1, file );
+    fwrite( &tmp, sizeof( tmp ), 1, file );
+}
+
+static void icvWriteVecSample( FILE* file, CvArr* sample )
+{
+    CvMat* mat, stub;
+    int r, c;
+    short tmp;
+    uchar chartmp;
+
+    mat = cvGetMat( sample, &stub );
+    chartmp = 0;
+    fwrite( &chartmp, sizeof( chartmp ), 1, file );
+    for( r = 0; r < mat->rows; r++ )
+    {
+        for( c = 0; c < mat->cols; c++ )
+        {
+            tmp = (short) (CV_MAT_ELEM( *mat, uchar, r, c ));
+            fwrite( &tmp, sizeof( tmp ), 1, file );
+        }
+    }
+}
+
+/* Calculates coefficients of perspective transformation
+ * which maps <quad> into rectangle ((0,0), (w,0), (w,h), (h,0)):
+ *
+ *      c00*xi + c01*yi + c02
+ * ui = ---------------------
+ *      c20*xi + c21*yi + c22
+ *
+ *      c10*xi + c11*yi + c12
+ * vi = ---------------------
+ *      c20*xi + c21*yi + c22
+ *
+ * Coefficients are calculated by solving linear system:
+ * / x0 y0  1  0  0  0 -x0*u0 -y0*u0 \ /c00\ /u0\
+ * | x1 y1  1  0  0  0 -x1*u1 -y1*u1 | |c01| |u1|
+ * | x2 y2  1  0  0  0 -x2*u2 -y2*u2 | |c02| |u2|
+ * | x3 y3  1  0  0  0 -x3*u3 -y3*u3 |.|c10|=|u3|,
+ * |  0  0  0 x0 y0  1 -x0*v0 -y0*v0 | |c11| |v0|
+ * |  0  0  0 x1 y1  1 -x1*v1 -y1*v1 | |c12| |v1|
+ * |  0  0  0 x2 y2  1 -x2*v2 -y2*v2 | |c20| |v2|
+ * \  0  0  0 x3 y3  1 -x3*v3 -y3*v3 / \c21/ \v3/
+ *
+ * where:
+ *   (xi, yi) = (quad[i][0], quad[i][1])
+ *        cij - coeffs[i][j], coeffs[2][2] = 1
+ *   (ui, vi) - rectangle vertices
+ */
+static void cvGetPerspectiveTransform( CvSize src_size, double quad[4][2], double coeffs[3][3] )
+{
+    //CV_FUNCNAME( "cvWarpPerspective" );
+
+    __BEGIN__;
+
+    double a[8][8];
+    double b[8];
+
+    CvMat A = cvMat( 8, 8, CV_64FC1, a );
+    CvMat B = cvMat( 8, 1, CV_64FC1, b );
+    CvMat X = cvMat( 8, 1, CV_64FC1, coeffs );
+
+    int i;
+    for( i = 0; i < 4; ++i )
+    {
+        a[i][0] = quad[i][0]; a[i][1] = quad[i][1]; a[i][2] = 1;
+        a[i][3] = a[i][4] = a[i][5] = a[i][6] = a[i][7] = 0;
+        b[i] = 0;
+    }
+    for( i = 4; i < 8; ++i )
+    {
+        a[i][3] = quad[i-4][0]; a[i][4] = quad[i-4][1]; a[i][5] = 1;
+        a[i][0] = a[i][1] = a[i][2] = a[i][6] = a[i][7] = 0;
+        b[i] = 0;
+    }
+
+    int u = src_size.width - 1;
+    int v = src_size.height - 1;
+
+    a[1][6] = -quad[1][0] * u; a[1][7] = -quad[1][1] * u;
+    a[2][6] = -quad[2][0] * u; a[2][7] = -quad[2][1] * u;
+    b[1] = b[2] = u;
+
+    a[6][6] = -quad[2][0] * v; a[6][7] = -quad[2][1] * v;
+    a[7][6] = -quad[3][0] * v; a[7][7] = -quad[3][1] * v;
+    b[6] = b[7] = v;
+
+    cvSolve( &A, &B, &X );
+
+    coeffs[2][2] = 1;
+
+    __END__;
+}
+
+/* Warps source into destination by a perspective transform */
+static void cvWarpPerspective( CvArr* src, CvArr* dst, double quad[4][2] )
+{
+    CV_FUNCNAME( "cvWarpPerspective" );
+
+    __BEGIN__;
+
+#ifdef __IPL_H__
+    IplImage src_stub, dst_stub;
+    IplImage* src_img;
+    IplImage* dst_img;
+    CV_CALL( src_img = cvGetImage( src, &src_stub ) );
+    CV_CALL( dst_img = cvGetImage( dst, &dst_stub ) );
+    iplWarpPerspectiveQ( src_img, dst_img, quad, IPL_WARP_R_TO_Q,
+                         IPL_INTER_CUBIC | IPL_SMOOTH_EDGE );
+#else
+
+    int fill_value = 0;
+
+    double c[3][3]; /* transformation coefficients */
+    double q[4][2]; /* rearranged quad */
+
+    int left = 0;
+    int right = 0;
+    int next_right = 0;
+    int next_left = 0;
+    double y_min = 0;
+    double y_max = 0;
+    double k_left, b_left, k_right, b_right;
+
+    uchar* src_data;
+    int src_step;
+    CvSize src_size;
+
+    uchar* dst_data;
+    int dst_step;
+    CvSize dst_size;
+
+    double d = 0;
+    int direction = 0;
+    int i;
+
+    if( !src || (!CV_IS_IMAGE( src ) && !CV_IS_MAT( src )) ||
+        cvGetElemType( src ) != CV_8UC1 ||
+        cvGetDims( src ) != 2 )
+    {
+        CV_ERROR( CV_StsBadArg,
+            "Source must be two-dimensional array of CV_8UC1 type." );
+    }
+    if( !dst || (!CV_IS_IMAGE( dst ) && !CV_IS_MAT( dst )) ||
+        cvGetElemType( dst ) != CV_8UC1 ||
+        cvGetDims( dst ) != 2 )
+    {
+        CV_ERROR( CV_StsBadArg,
+            "Destination must be two-dimensional array of CV_8UC1 type." );
+    }
+
+    CV_CALL( cvGetRawData( src, &src_data, &src_step, &src_size ) );
+    CV_CALL( cvGetRawData( dst, &dst_data, &dst_step, &dst_size ) );
+
+    CV_CALL( cvGetPerspectiveTransform( src_size, quad, c ) );
+
+    /* if direction > 0 then vertices in quad follow in a CW direction,
+       otherwise they follow in a CCW direction */
+    direction = 0;
+    for( i = 0; i < 4; ++i )
+    {
+        int ni = i + 1; if( ni == 4 ) ni = 0;
+        int pi = i - 1; if( pi == -1 ) pi = 3;
+
+        d = (quad[i][0] - quad[pi][0])*(quad[ni][1] - quad[i][1]) -
+            (quad[i][1] - quad[pi][1])*(quad[ni][0] - quad[i][0]);
+        int cur_direction = CV_SIGN(d);
+        if( direction == 0 )
+        {
+            direction = cur_direction;
+        }
+        else if( direction * cur_direction < 0 )
+        {
+            direction = 0;
+            break;
+        }
+    }
+    if( direction == 0 )
+    {
+        CV_ERROR( CV_StsBadArg, "Quadrangle is nonconvex or degenerated." );
+    }
+
+    /* <left> is the index of the topmost quad vertice
+       if there are two such vertices <left> is the leftmost one */
+    left = 0;
+    for( i = 1; i < 4; ++i )
+    {
+        if( (quad[i][1] < quad[left][1]) ||
+            ((quad[i][1] == quad[left][1]) && (quad[i][0] < quad[left][0])) )
+        {
+            left = i;
+        }
+    }
+    /* rearrange <quad> vertices in such way that they follow in a CW
+       direction and the first vertice is the topmost one and put them
+       into <q> */
+    if( direction > 0 )
+    {
+        for( i = left; i < 4; ++i )
+        {
+            q[i-left][0] = quad[i][0];
+            q[i-left][1] = quad[i][1];
+        }
+        for( i = 0; i < left; ++i )
+        {
+            q[4-left+i][0] = quad[i][0];
+            q[4-left+i][1] = quad[i][1];
+        }
+    }
+    else
+    {
+        for( i = left; i >= 0; --i )
+        {
+            q[left-i][0] = quad[i][0];
+            q[left-i][1] = quad[i][1];
+        }
+        for( i = 3; i > left; --i )
+        {
+            q[4+left-i][0] = quad[i][0];
+            q[4+left-i][1] = quad[i][1];
+        }
+    }
+
+    left = right = 0;
+    /* if there are two topmost points, <right> is the index of the rightmost one
+       otherwise <right> */
+    if( q[left][1] == q[left+1][1] )
+    {
+        right = 1;
+    }
+
+    /* <next_left> follows <left> in a CCW direction */
+    next_left = 3;
+    /* <next_right> follows <right> in a CW direction */
+    next_right = right + 1;
+
+    /* subtraction of 1 prevents skipping of the first row */
+    y_min = q[left][1] - 1;
+
+    /* left edge equation: y = k_left * x + b_left */
+    k_left = (q[left][0] - q[next_left][0]) /
+               (q[left][1] - q[next_left][1]);
+    b_left = (q[left][1] * q[next_left][0] -
+               q[left][0] * q[next_left][1]) /
+                 (q[left][1] - q[next_left][1]);
+
+    /* right edge equation: y = k_right * x + b_right */
+    k_right = (q[right][0] - q[next_right][0]) /
+               (q[right][1] - q[next_right][1]);
+    b_right = (q[right][1] * q[next_right][0] -
+               q[right][0] * q[next_right][1]) /
+                 (q[right][1] - q[next_right][1]);
+
+    for(;;)
+    {
+        int x, y;
+
+        y_max = MIN( q[next_left][1], q[next_right][1] );
+
+        int iy_min = MAX( cvRound(y_min), 0 ) + 1;
+        int iy_max = MIN( cvRound(y_max), dst_size.height - 1 );
+
+        double x_min = k_left * iy_min + b_left;
+        double x_max = k_right * iy_min + b_right;
+
+        /* walk through the destination quadrangle row by row */
+        for( y = iy_min; y <= iy_max; ++y )
+        {
+            int ix_min = MAX( cvRound( x_min ), 0 );
+            int ix_max = MIN( cvRound( x_max ), dst_size.width - 1 );
+
+            for( x = ix_min; x <= ix_max; ++x )
+            {
+                /* calculate coordinates of the corresponding source array point */
+                double div = (c[2][0] * x + c[2][1] * y + c[2][2]);
+                double src_x = (c[0][0] * x + c[0][1] * y + c[0][2]) / div;
+                double src_y = (c[1][0] * x + c[1][1] * y + c[1][2]) / div;
+
+                int isrc_x = cvFloor( src_x );
+                int isrc_y = cvFloor( src_y );
+                double delta_x = src_x - isrc_x;
+                double delta_y = src_y - isrc_y;
+
+                uchar* s = src_data + isrc_y * src_step + isrc_x;
+
+                int i00, i10, i01, i11;
+                i00 = i10 = i01 = i11 = (int) fill_value;
+
+                /* linear interpolation using 2x2 neighborhood */
+                if( isrc_x >= 0 && isrc_x <= src_size.width &&
+                    isrc_y >= 0 && isrc_y <= src_size.height )
+                {
+                    i00 = s[0];
+                }
+                if( isrc_x >= -1 && isrc_x < src_size.width &&
+                    isrc_y >= 0 && isrc_y <= src_size.height )
+                {
+                    i10 = s[1];
+                }
+                if( isrc_x >= 0 && isrc_x <= src_size.width &&
+                    isrc_y >= -1 && isrc_y < src_size.height )
+                {
+                    i01 = s[src_step];
+                }
+                if( isrc_x >= -1 && isrc_x < src_size.width &&
+                    isrc_y >= -1 && isrc_y < src_size.height )
+                {
+                    i11 = s[src_step+1];
+                }
+
+                double i0 = i00 + (i10 - i00)*delta_x;
+                double i1 = i01 + (i11 - i01)*delta_x;
+
+                ((uchar*)(dst_data + y * dst_step))[x] = (uchar) (i0 + (i1 - i0)*delta_y);
+            }
+            x_min += k_left;
+            x_max += k_right;
+        }
+
+        if( (next_left == next_right) ||
+            (next_left+1 == next_right && q[next_left][1] == q[next_right][1]) )
+        {
+            break;
+        }
+
+        if( y_max == q[next_left][1] )
+        {
+            left = next_left;
+            next_left = left - 1;
+
+            k_left = (q[left][0] - q[next_left][0]) /
+                       (q[left][1] - q[next_left][1]);
+            b_left = (q[left][1] * q[next_left][0] -
+                       q[left][0] * q[next_left][1]) /
+                         (q[left][1] - q[next_left][1]);
+        }
+        if( y_max == q[next_right][1] )
+        {
+            right = next_right;
+            next_right = right + 1;
+
+            k_right = (q[right][0] - q[next_right][0]) /
+                       (q[right][1] - q[next_right][1]);
+            b_right = (q[right][1] * q[next_right][0] -
+                       q[right][0] * q[next_right][1]) /
+                         (q[right][1] - q[next_right][1]);
+        }
+        y_min = y_max;
+    }
+#endif /* #ifndef __IPL_H__ */
+
+    __END__;
+}
+
+static
+void icvRandomQuad( int width, int height, double quad[4][2],
+                    double maxxangle,
+                    double maxyangle,
+                    double maxzangle )
+{
+    double distfactor = 3.0;
+    double distfactor2 = 1.0;
+
+    double halfw, halfh;
+    int i;
+
+    double rotVectData[3];
+    double vectData[3];
+    double rotMatData[9];
+
+    CvMat rotVect;
+    CvMat rotMat;
+    CvMat vect;
+
+    double d;
+
+    rotVect = cvMat( 3, 1, CV_64FC1, &rotVectData[0] );
+    rotMat = cvMat( 3, 3, CV_64FC1, &rotMatData[0] );
+    vect = cvMat( 3, 1, CV_64FC1, &vectData[0] );
+
+    rotVectData[0] = maxxangle * (2.0 * rand() / RAND_MAX - 1.0);
+    rotVectData[1] = ( maxyangle - fabs( rotVectData[0] ) )
+        * (2.0 * rand() / RAND_MAX - 1.0);
+    rotVectData[2] = maxzangle * (2.0 * rand() / RAND_MAX - 1.0);
+    d = (distfactor + distfactor2 * (2.0 * rand() / RAND_MAX - 1.0)) * width;
+
+/*
+    rotVectData[0] = maxxangle;
+    rotVectData[1] = maxyangle;
+    rotVectData[2] = maxzangle;
+
+    d = distfactor * width;
+*/
+
+    cvRodrigues2( &rotVect, &rotMat );
+
+    halfw = 0.5 * width;
+    halfh = 0.5 * height;
+
+    quad[0][0] = -halfw;
+    quad[0][1] = -halfh;
+    quad[1][0] =  halfw;
+    quad[1][1] = -halfh;
+    quad[2][0] =  halfw;
+    quad[2][1] =  halfh;
+    quad[3][0] = -halfw;
+    quad[3][1] =  halfh;
+
+    for( i = 0; i < 4; i++ )
+    {
+        rotVectData[0] = quad[i][0];
+        rotVectData[1] = quad[i][1];
+        rotVectData[2] = 0.0;
+        cvMatMulAdd( &rotMat, &rotVect, 0, &vect );
+        quad[i][0] = vectData[0] * d / (d + vectData[2]) + halfw;
+        quad[i][1] = vectData[1] * d / (d + vectData[2]) + halfh;
+
+        /*
+        quad[i][0] += halfw;
+        quad[i][1] += halfh;
+        */
+    }
+}
+
+
+typedef struct CvSampleDistortionData
+{
+    IplImage* src;
+    IplImage* erode;
+    IplImage* dilate;
+    IplImage* mask;
+    IplImage* img;
+    IplImage* maskimg;
+    int dx;
+    int dy;
+    int bgcolor;
+} CvSampleDistortionData;
+
+#if defined CV_OPENMP && (defined _MSC_VER || defined CV_ICC)
+#define CV_OPENMP 1
+#else
+#undef CV_OPENMP
+#endif
+
+typedef struct CvBackgroundData
+{
+    int    count;
+    char** filename;
+    int    last;
+    int    round;
+    CvSize winsize;
+} CvBackgroundData;
+
+typedef struct CvBackgroundReader
+{
+    CvMat   src;
+    CvMat   img;
+    CvPoint offset;
+    float   scale;
+    float   scalefactor;
+    float   stepfactor;
+    CvPoint point;
+} CvBackgroundReader;
+
+/*
+ * Background reader
+ * Created in each thread
+ */
+CvBackgroundReader* cvbgreader = NULL;
+
+#if defined CV_OPENMP
+#pragma omp threadprivate(cvbgreader)
+#endif
+
+CvBackgroundData* cvbgdata = NULL;
+
+static int icvStartSampleDistortion( const char* imgfilename, int bgcolor, int bgthreshold,
+                              CvSampleDistortionData* data )
+{
+    memset( data, 0, sizeof( *data ) );
+    data->src = cvLoadImage( imgfilename, 0 );
+    if( data->src != NULL && data->src->nChannels == 1
+        && data->src->depth == IPL_DEPTH_8U )
+    {
+        int r, c;
+        uchar* pmask;
+        uchar* psrc;
+        uchar* perode;
+        uchar* pdilate;
+        uchar dd, de;
+
+        data->dx = data->src->width / 2;
+        data->dy = data->src->height / 2;
+        data->bgcolor = bgcolor;
+
+        data->mask = cvCloneImage( data->src );
+        data->erode = cvCloneImage( data->src );
+        data->dilate = cvCloneImage( data->src );
+
+        /* make mask image */
+        for( r = 0; r < data->mask->height; r++ )
+        {
+            for( c = 0; c < data->mask->width; c++ )
+            {
+                pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
+                        + c );
+                if( bgcolor - bgthreshold <= (int) (*pmask) &&
+                    (int) (*pmask) <= bgcolor + bgthreshold )
+                {
+                    *pmask = (uchar) 0;
+                }
+                else
+                {
+                    *pmask = (uchar) 255;
+                }
+            }
+        }
+
+        /* extend borders of source image */
+        cvErode( data->src, data->erode, 0, 1 );
+        cvDilate( data->src, data->dilate, 0, 1 );
+        for( r = 0; r < data->mask->height; r++ )
+        {
+            for( c = 0; c < data->mask->width; c++ )
+            {
+                pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
+                        + c );
+                if( (*pmask) == 0 )
+                {
+                    psrc = ( (uchar*) (data->src->imageData + r * data->src->widthStep)
+                           + c );
+                    perode =
+                        ( (uchar*) (data->erode->imageData + r * data->erode->widthStep)
+                                + c );
+                    pdilate =
+                        ( (uchar*)(data->dilate->imageData + r * data->dilate->widthStep)
+                                + c );
+                    de = (uchar)(bgcolor - (*perode));
+                    dd = (uchar)((*pdilate) - bgcolor);
+                    if( de >= dd && de > bgthreshold )
+                    {
+                        (*psrc) = (*perode);
+                    }
+                    if( dd > de && dd > bgthreshold )
+                    {
+                        (*psrc) = (*pdilate);
+                    }
+                }
+            }
+        }
+
+        data->img = cvCreateImage( cvSize( data->src->width + 2 * data->dx,
+                                           data->src->height + 2 * data->dy ),
+                                   IPL_DEPTH_8U, 1 );
+        data->maskimg = cvCloneImage( data->img );
+
+        return 1;
+    }
+
+    return 0;
+}
+
+static
+void icvPlaceDistortedSample( CvArr* background,
+                              int inverse, int maxintensitydev,
+                              double maxxangle, double maxyangle, double maxzangle,
+                              int inscribe, double maxshiftf, double maxscalef,
+                              CvSampleDistortionData* data )
+{
+    double quad[4][2];
+    int r, c;
+    uchar* pimg;
+    uchar* pbg;
+    uchar* palpha;
+    uchar chartmp;
+    int forecolordev;
+    float scale;
+    IplImage* img;
+    IplImage* maskimg;
+    CvMat  stub;
+    CvMat* bgimg;
+
+    CvRect cr;
+    CvRect roi;
+
+    double xshift, yshift, randscale;
+
+    icvRandomQuad( data->src->width, data->src->height, quad,
+                   maxxangle, maxyangle, maxzangle );
+    quad[0][0] += (double) data->dx;
+    quad[0][1] += (double) data->dy;
+    quad[1][0] += (double) data->dx;
+    quad[1][1] += (double) data->dy;
+    quad[2][0] += (double) data->dx;
+    quad[2][1] += (double) data->dy;
+    quad[3][0] += (double) data->dx;
+    quad[3][1] += (double) data->dy;
+
+    cvSet( data->img, cvScalar( data->bgcolor ) );
+    cvSet( data->maskimg, cvScalar( 0.0 ) );
+
+    cvWarpPerspective( data->src, data->img, quad );
+    cvWarpPerspective( data->mask, data->maskimg, quad );
+
+    cvSmooth( data->maskimg, data->maskimg, CV_GAUSSIAN, 3, 3 );
+
+    bgimg = cvGetMat( background, &stub );
+
+    cr.x = data->dx;
+    cr.y = data->dy;
+    cr.width = data->src->width;
+    cr.height = data->src->height;
+
+    if( inscribe )
+    {
+        /* quad's circumscribing rectangle */
+        cr.x = (int) MIN( quad[0][0], quad[3][0] );
+        cr.y = (int) MIN( quad[0][1], quad[1][1] );
+        cr.width  = (int) (MAX( quad[1][0], quad[2][0] ) + 0.5F ) - cr.x;
+        cr.height = (int) (MAX( quad[2][1], quad[3][1] ) + 0.5F ) - cr.y;
+    }
+
+    xshift = maxshiftf * rand() / RAND_MAX;
+    yshift = maxshiftf * rand() / RAND_MAX;
+
+    cr.x -= (int) ( xshift * cr.width  );
+    cr.y -= (int) ( yshift * cr.height );
+    cr.width  = (int) ((1.0 + maxshiftf) * cr.width );
+    cr.height = (int) ((1.0 + maxshiftf) * cr.height);
+
+    randscale = maxscalef * rand() / RAND_MAX;
+    cr.x -= (int) ( 0.5 * randscale * cr.width  );
+    cr.y -= (int) ( 0.5 * randscale * cr.height );
+    cr.width  = (int) ((1.0 + randscale) * cr.width );
+    cr.height = (int) ((1.0 + randscale) * cr.height);
+
+    scale = MAX( ((float) cr.width) / bgimg->cols, ((float) cr.height) / bgimg->rows );
+
+    roi.x = (int) (-0.5F * (scale * bgimg->cols - cr.width) + cr.x);
+    roi.y = (int) (-0.5F * (scale * bgimg->rows - cr.height) + cr.y);
+    roi.width  = (int) (scale * bgimg->cols);
+    roi.height = (int) (scale * bgimg->rows);
+
+    img = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
+    maskimg = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
+
+    cvSetImageROI( data->img, roi );
+    cvResize( data->img, img );
+    cvResetImageROI( data->img );
+    cvSetImageROI( data->maskimg, roi );
+    cvResize( data->maskimg, maskimg );
+    cvResetImageROI( data->maskimg );
+
+    forecolordev = (int) (maxintensitydev * (2.0 * rand() / RAND_MAX - 1.0));
+
+    for( r = 0; r < img->height; r++ )
+    {
+        for( c = 0; c < img->width; c++ )
+        {
+            pimg = (uchar*) img->imageData + r * img->widthStep + c;
+            pbg = (uchar*) bgimg->data.ptr + r * bgimg->step + c;
+            palpha = (uchar*) maskimg->imageData + r * maskimg->widthStep + c;
+            chartmp = (uchar) MAX( 0, MIN( 255, forecolordev + (*pimg) ) );
+            if( inverse )
+            {
+                chartmp ^= 0xFF;
+            }
+            *pbg = (uchar) (( chartmp*(*palpha )+(255 - (*palpha) )*(*pbg) ) / 255);
+        }
+    }
+
+    cvReleaseImage( &img );
+    cvReleaseImage( &maskimg );
+}
+
+static
+void icvEndSampleDistortion( CvSampleDistortionData* data )
+{
+    if( data->src )
+    {
+        cvReleaseImage( &data->src );
+    }
+    if( data->mask )
+    {
+        cvReleaseImage( &data->mask );
+    }
+    if( data->erode )
+    {
+        cvReleaseImage( &data->erode );
+    }
+    if( data->dilate )
+    {
+        cvReleaseImage( &data->dilate );
+    }
+    if( data->img )
+    {
+        cvReleaseImage( &data->img );
+    }
+    if( data->maskimg )
+    {
+        cvReleaseImage( &data->maskimg );
+    }
+}
+
+static
+CvBackgroundData* icvCreateBackgroundData( const char* filename, CvSize winsize )
+{
+    CvBackgroundData* data = NULL;
+
+    const char* dir = NULL;
+    char full[PATH_MAX];
+    char* imgfilename = NULL;
+    size_t datasize = 0;
+    int    count = 0;
+    FILE*  input = NULL;
+    char*  tmp   = NULL;
+    int    len   = 0;
+
+    assert( filename != NULL );
+
+    dir = strrchr( filename, '\\' );
+    if( dir == NULL )
+    {
+        dir = strrchr( filename, '/' );
+    }
+    if( dir == NULL )
+    {
+        imgfilename = &(full[0]);
+    }
+    else
+    {
+        strncpy( &(full[0]), filename, (dir - filename + 1) );
+        imgfilename = &(full[(dir - filename + 1)]);
+    }
+
+    input = fopen( filename, "r" );
+    if( input != NULL )
+    {
+        count = 0;
+        datasize = 0;
+
+        /* count */
+        while( !feof( input ) )
+        {
+            *imgfilename = '\0';
+            if( !fgets( imgfilename, PATH_MAX - (int)(imgfilename - full) - 1, input ))
+                break;
+            len = (int)strlen( imgfilename );
+            for( ; len > 0 && isspace(imgfilename[len-1]); len-- )
+                imgfilename[len-1] = '\0';
+            if( len > 0 )
+            {
+                if( (*imgfilename) == '#' ) continue; /* comment */
+                count++;
+                datasize += sizeof( char ) * (strlen( &(full[0]) ) + 1);
+            }
+        }
+        if( count > 0 )
+        {
+            //rewind( input );
+            fseek( input, 0, SEEK_SET );
+            datasize += sizeof( *data ) + sizeof( char* ) * count;
+            data = (CvBackgroundData*) cvAlloc( datasize );
+            memset( (void*) data, 0, datasize );
+            data->count = count;
+            data->filename = (char**) (data + 1);
+            data->last = 0;
+            data->round = 0;
+            data->winsize = winsize;
+            tmp = (char*) (data->filename + data->count);
+            count = 0;
+            while( !feof( input ) )
+            {
+                *imgfilename = '\0';
+                if( !fgets( imgfilename, PATH_MAX - (int)(imgfilename - full) - 1, input ))
+                    break;
+                len = (int)strlen( imgfilename );
+                if( len > 0 && imgfilename[len-1] == '\n' )
+                    imgfilename[len-1] = 0, len--;
+                if( len > 0 )
+                {
+                    if( (*imgfilename) == '#' ) continue; /* comment */
+                    data->filename[count++] = tmp;
+                    strcpy( tmp, &(full[0]) );
+                    tmp += strlen( &(full[0]) ) + 1;
+                }
+            }
+        }
+        fclose( input );
+    }
+
+    return data;
+}
+
+static
+void icvReleaseBackgroundData( CvBackgroundData** data )
+{
+    assert( data != NULL && (*data) != NULL );
+
+    cvFree( data );
+}
+
+static
+CvBackgroundReader* icvCreateBackgroundReader()
+{
+    CvBackgroundReader* reader = NULL;
+
+    reader = (CvBackgroundReader*) cvAlloc( sizeof( *reader ) );
+    memset( (void*) reader, 0, sizeof( *reader ) );
+    reader->src = cvMat( 0, 0, CV_8UC1, NULL );
+    reader->img = cvMat( 0, 0, CV_8UC1, NULL );
+    reader->offset = cvPoint( 0, 0 );
+    reader->scale       = 1.0F;
+    reader->scalefactor = 1.4142135623730950488016887242097F;
+    reader->stepfactor  = 0.5F;
+    reader->point = reader->offset;
+
+    return reader;
+}
+
+static
+void icvReleaseBackgroundReader( CvBackgroundReader** reader )
+{
+    assert( reader != NULL && (*reader) != NULL );
+
+    if( (*reader)->src.data.ptr != NULL )
+    {
+        cvFree( &((*reader)->src.data.ptr) );
+    }
+    if( (*reader)->img.data.ptr != NULL )
+    {
+        cvFree( &((*reader)->img.data.ptr) );
+    }
+
+    cvFree( reader );
+}
+
+static
+void icvGetNextFromBackgroundData( CvBackgroundData* data,
+                                   CvBackgroundReader* reader )
+{
+    IplImage* img = NULL;
+    size_t datasize = 0;
+    int round = 0;
+    int i = 0;
+    CvPoint offset = cvPoint(0,0);
+
+    assert( data != NULL && reader != NULL );
+
+    if( reader->src.data.ptr != NULL )
+    {
+        cvFree( &(reader->src.data.ptr) );
+        reader->src.data.ptr = NULL;
+    }
+    if( reader->img.data.ptr != NULL )
+    {
+        cvFree( &(reader->img.data.ptr) );
+        reader->img.data.ptr = NULL;
+    }
+
+    #ifdef CV_OPENMP
+    #pragma omp critical(c_background_data)
+    #endif /* CV_OPENMP */
+    {
+        for( i = 0; i < data->count; i++ )
+        {
+            round = data->round;
+
+#ifdef CV_VERBOSE
+            printf( "Open background image: %s\n", data->filename[data->last] );
+#endif /* CV_VERBOSE */
+
+            data->last = rand() % data->count;
+            data->last %= data->count;
+            img = cvLoadImage( data->filename[data->last], 0 );
+            if( !img )
+                continue;
+            data->round += data->last / data->count;
+            data->round = data->round % (data->winsize.width * data->winsize.height);
+
+            offset.x = round % data->winsize.width;
+            offset.y = round / data->winsize.width;
+
+            offset.x = MIN( offset.x, img->width - data->winsize.width );
+            offset.y = MIN( offset.y, img->height - data->winsize.height );
+
+            if( img != NULL && img->depth == IPL_DEPTH_8U && img->nChannels == 1 &&
+                offset.x >= 0 && offset.y >= 0 )
+            {
+                break;
+            }
+            if( img != NULL )
+                cvReleaseImage( &img );
+            img = NULL;
+        }
+    }
+    if( img == NULL )
+    {
+        /* no appropriate image */
+
+#ifdef CV_VERBOSE
+        printf( "Invalid background description file.\n" );
+#endif /* CV_VERBOSE */
+
+        assert( 0 );
+        exit( 1 );
+    }
+    datasize = sizeof( uchar ) * img->width * img->height;
+    reader->src = cvMat( img->height, img->width, CV_8UC1, (void*) cvAlloc( datasize ) );
+    cvCopy( img, &reader->src, NULL );
+    cvReleaseImage( &img );
+    img = NULL;
+
+    //reader->offset.x = round % data->winsize.width;
+    //reader->offset.y = round / data->winsize.width;
+    reader->offset = offset;
+    reader->point = reader->offset;
+    reader->scale = MAX(
+        ((float) data->winsize.width + reader->point.x) / ((float) reader->src.cols),
+        ((float) data->winsize.height + reader->point.y) / ((float) reader->src.rows) );
+
+    reader->img = cvMat( (int) (reader->scale * reader->src.rows + 0.5F),
+                         (int) (reader->scale * reader->src.cols + 0.5F),
+                          CV_8UC1, (void*) cvAlloc( datasize ) );
+    cvResize( &(reader->src), &(reader->img) );
+}
+
+/*
+ * icvGetBackgroundImage
+ *
+ * Get an image from background
+ * <img> must be allocated and have size, previously passed to icvInitBackgroundReaders
+ *
+ * Usage example:
+ * icvInitBackgroundReaders( "bg.txt", cvSize( 24, 24 ) );
+ * ...
+ * #pragma omp parallel
+ * {
+ *     ...
+ *     icvGetBackgourndImage( cvbgdata, cvbgreader, img );
+ *     ...
+ * }
+ * ...
+ * icvDestroyBackgroundReaders();
+ */
+static
+void icvGetBackgroundImage( CvBackgroundData* data,
+                            CvBackgroundReader* reader,
+                            CvMat* img )
+{
+    CvMat mat;
+
+    assert( data != NULL && reader != NULL && img != NULL );
+    assert( CV_MAT_TYPE( img->type ) == CV_8UC1 );
+    assert( img->cols == data->winsize.width );
+    assert( img->rows == data->winsize.height );
+
+    if( reader->img.data.ptr == NULL )
+    {
+        icvGetNextFromBackgroundData( data, reader );
+    }
+
+    mat = cvMat( data->winsize.height, data->winsize.width, CV_8UC1 );
+    cvSetData( &mat, (void*) (reader->img.data.ptr + reader->point.y * reader->img.step
+                              + reader->point.x * sizeof( uchar )), reader->img.step );
+
+    cvCopy( &mat, img, 0 );
+    if( (int) ( reader->point.x + (1.0F + reader->stepfactor ) * data->winsize.width )
+            < reader->img.cols )
+    {
+        reader->point.x += (int) (reader->stepfactor * data->winsize.width);
+    }
+    else
+    {
+        reader->point.x = reader->offset.x;
+        if( (int) ( reader->point.y + (1.0F + reader->stepfactor ) * data->winsize.height )
+                < reader->img.rows )
+        {
+            reader->point.y += (int) (reader->stepfactor * data->winsize.height);
+        }
+        else
+        {
+            reader->point.y = reader->offset.y;
+            reader->scale *= reader->scalefactor;
+            if( reader->scale <= 1.0F )
+            {
+                reader->img = cvMat( (int) (reader->scale * reader->src.rows),
+                                     (int) (reader->scale * reader->src.cols),
+                                      CV_8UC1, (void*) (reader->img.data.ptr) );
+                cvResize( &(reader->src), &(reader->img) );
+            }
+            else
+            {
+                icvGetNextFromBackgroundData( data, reader );
+            }
+        }
+    }
+}
+
+/*
+ * icvInitBackgroundReaders
+ *
+ * Initialize background reading process.
+ * <cvbgreader> and <cvbgdata> are initialized.
+ * Must be called before any usage of background
+ *
+ * filename - name of background description file
+ * winsize  - size of images will be obtained from background
+ *
+ * return 1 on success, 0 otherwise.
+ */
+static int icvInitBackgroundReaders( const char* filename, CvSize winsize )
+{
+    if( cvbgdata == NULL && filename != NULL )
+    {
+        cvbgdata = icvCreateBackgroundData( filename, winsize );
+    }
+
+    if( cvbgdata )
+    {
+
+        #ifdef CV_OPENMP
+        #pragma omp parallel
+        #endif /* CV_OPENMP */
+        {
+            #ifdef CV_OPENMP
+            #pragma omp critical(c_create_bg_data)
+            #endif /* CV_OPENMP */
+            {
+                if( cvbgreader == NULL )
+                {
+                    cvbgreader = icvCreateBackgroundReader();
+                }
+            }
+        }
+
+    }
+
+    return (cvbgdata != NULL);
+}
+
+/*
+ * icvDestroyBackgroundReaders
+ *
+ * Finish backgournd reading process
+ */
+static
+void icvDestroyBackgroundReaders()
+{
+    /* release background reader in each thread */
+    #ifdef CV_OPENMP
+    #pragma omp parallel
+    #endif /* CV_OPENMP */
+    {
+        #ifdef CV_OPENMP
+        #pragma omp critical(c_release_bg_data)
+        #endif /* CV_OPENMP */
+        {
+            if( cvbgreader != NULL )
+            {
+                icvReleaseBackgroundReader( &cvbgreader );
+                cvbgreader = NULL;
+            }
+        }
+    }
+
+    if( cvbgdata != NULL )
+    {
+        icvReleaseBackgroundData( &cvbgdata );
+        cvbgdata = NULL;
+    }
+}
+
+void cvCreateTrainingSamples( const char* filename,
+                              const char* imgfilename, int bgcolor, int bgthreshold,
+                              const char* bgfilename, int count,
+                              int invert, int maxintensitydev,
+                              double maxxangle, double maxyangle, double maxzangle,
+                              int showsamples,
+                              int winwidth, int winheight )
+{
+    CvSampleDistortionData data;
+
+    assert( filename != NULL );
+    assert( imgfilename != NULL );
+
+    if( !icvMkDir( filename ) )
+    {
+        fprintf( stderr, "Unable to create output file: %s\n", filename );
+        return;
+    }
+    if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
+    {
+        FILE* output = NULL;
+
+        output = fopen( filename, "wb" );
+        if( output != NULL )
+        {
+            int hasbg;
+            int i;
+            CvMat sample;
+            int inverse;
+
+            hasbg = 0;
+            hasbg = (bgfilename != NULL && icvInitBackgroundReaders( bgfilename,
+                     cvSize( winwidth,winheight ) ) );
+
+            sample = cvMat( winheight, winwidth, CV_8UC1, cvAlloc( sizeof( uchar ) *
+                            winheight * winwidth ) );
+
+            icvWriteVecHeader( output, count, sample.cols, sample.rows );
+
+            if( showsamples )
+            {
+                cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
+            }
+
+            inverse = invert;
+            for( i = 0; i < count; i++ )
+            {
+                if( hasbg )
+                {
+                    icvGetBackgroundImage( cvbgdata, cvbgreader, &sample );
+                }
+                else
+                {
+                    cvSet( &sample, cvScalar( bgcolor ) );
+                }
+
+                if( invert == CV_RANDOM_INVERT )
+                {
+                    inverse = (rand() > (RAND_MAX/2));
+                }
+                icvPlaceDistortedSample( &sample, inverse, maxintensitydev,
+                    maxxangle, maxyangle, maxzangle,
+                    0   /* nonzero means placing image without cut offs */,
+                    0.0 /* nozero adds random shifting                  */,
+                    0.0 /* nozero adds random scaling                   */,
+                    &data );
+
+                if( showsamples )
+                {
+                    cvShowImage( "Sample", &sample );
+                    if( cvWaitKey( 0 ) == 27 )
+                    {
+                        showsamples = 0;
+                    }
+                }
+
+                icvWriteVecSample( output, &sample );
+
+#ifdef CV_VERBOSE
+                if( i % 500 == 0 )
+                {
+                    printf( "\r%3d%%", 100 * i / count );
+                }
+#endif /* CV_VERBOSE */
+            }
+            icvDestroyBackgroundReaders();
+            cvFree( &(sample.data.ptr) );
+            fclose( output );
+        } /* if( output != NULL ) */
+
+        icvEndSampleDistortion( &data );
+    }
+
+#ifdef CV_VERBOSE
+    printf( "\r      \r" );
+#endif /* CV_VERBOSE */
+
+}
+
+#define CV_INFO_FILENAME "info.dat"
+
+void cvCreateTestSamples( const char* infoname,
+                          const char* imgfilename, int bgcolor, int bgthreshold,
+                          const char* bgfilename, int count,
+                          int invert, int maxintensitydev,
+                          double maxxangle, double maxyangle, double maxzangle,
+                          int showsamples,
+                          int winwidth, int winheight )
+{
+    CvSampleDistortionData data;
+
+    assert( infoname != NULL );
+    assert( imgfilename != NULL );
+    assert( bgfilename != NULL );
+
+    if( !icvMkDir( infoname ) )
+    {
+
+#if CV_VERBOSE
+        fprintf( stderr, "Unable to create directory hierarchy: %s\n", infoname );
+#endif /* CV_VERBOSE */
+
+        return;
+    }
+    if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
+    {
+        char fullname[PATH_MAX];
+        char* filename;
+        CvMat win;
+        FILE* info;
+
+        if( icvInitBackgroundReaders( bgfilename, cvSize( 10, 10 ) ) )
+        {
+            int i;
+            int x, y, width, height;
+            float scale;
+            float maxscale;
+            int inverse;
+
+            if( showsamples )
+            {
+                cvNamedWindow( "Image", CV_WINDOW_AUTOSIZE );
+            }
+
+            info = fopen( infoname, "w" );
+            strcpy( fullname, infoname );
+            filename = strrchr( fullname, '\\' );
+            if( filename == NULL )
+            {
+                filename = strrchr( fullname, '/' );
+            }
+            if( filename == NULL )
+            {
+                filename = fullname;
+            }
+            else
+            {
+                filename++;
+            }
+
+            count = MIN( count, cvbgdata->count );
+            inverse = invert;
+            for( i = 0; i < count; i++ )
+            {
+                icvGetNextFromBackgroundData( cvbgdata, cvbgreader );
+
+                maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
+                                   0.7F * cvbgreader->src.rows / winheight );
+                if( maxscale < 1.0F ) continue;
+
+                scale = (maxscale - 1.0F) * rand() / RAND_MAX + 1.0F;
+                width = (int) (scale * winwidth);
+                height = (int) (scale * winheight);
+                x = (int) ((0.1+0.8 * rand()/RAND_MAX) * (cvbgreader->src.cols - width));
+                y = (int) ((0.1+0.8 * rand()/RAND_MAX) * (cvbgreader->src.rows - height));
+
+                cvGetSubArr( &cvbgreader->src, &win, cvRect( x, y ,width, height ) );
+                if( invert == CV_RANDOM_INVERT )
+                {
+                    inverse = (rand() > (RAND_MAX/2));
+                }
+                icvPlaceDistortedSample( &win, inverse, maxintensitydev,
+                                         maxxangle, maxyangle, maxzangle,
+                                         1, 0.0, 0.0, &data );
+
+
+                sprintf( filename, "%04d_%04d_%04d_%04d_%04d.jpg",
+                         (i + 1), x, y, width, height );
+
+                if( info )
+                {
+                    fprintf( info, "%s %d %d %d %d %d\n",
+                        filename, 1, x, y, width, height );
+                }
+
+                cvSaveImage( fullname, &cvbgreader->src );
+                if( showsamples )
+                {
+                    cvShowImage( "Image", &cvbgreader->src );
+                    if( cvWaitKey( 0 ) == 27 )
+                    {
+                        showsamples = 0;
+                    }
+                }
+            }
+            if( info ) fclose( info );
+            icvDestroyBackgroundReaders();
+        }
+        icvEndSampleDistortion( &data );
+    }
+}
+
+
+int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
+                                     int num,
+                                     int showsamples,
+                                     int winwidth, int winheight )
+{
+    char fullname[PATH_MAX];
+    char* filename;
+
+    FILE* info;
+    FILE* vec;
+    IplImage* src=0;
+    IplImage* sample;
+    int line;
+    int error;
+    int i;
+    int x, y, width, height;
+    int total;
+
+    assert( infoname != NULL );
+    assert( vecfilename != NULL );
+
+    total = 0;
+    if( !icvMkDir( vecfilename ) )
+    {
+
+#if CV_VERBOSE
+        fprintf( stderr, "Unable to create directory hierarchy: %s\n", vecfilename );
+#endif /* CV_VERBOSE */
+
+        return total;
+    }
+
+    info = fopen( infoname, "r" );
+    if( info == NULL )
+    {
+
+#if CV_VERBOSE
+        fprintf( stderr, "Unable to open file: %s\n", infoname );
+#endif /* CV_VERBOSE */
+
+        return total;
+    }
+
+    vec = fopen( vecfilename, "wb" );
+    if( vec == NULL )
+    {
+
+#if CV_VERBOSE
+        fprintf( stderr, "Unable to open file: %s\n", vecfilename );
+#endif /* CV_VERBOSE */
+
+        fclose( info );
+
+        return total;
+    }
+
+    sample = cvCreateImage( cvSize( winwidth, winheight ), IPL_DEPTH_8U, 1 );
+
+    icvWriteVecHeader( vec, num, sample->width, sample->height );
+
+    if( showsamples )
+    {
+        cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
+    }
+
+    strcpy( fullname, infoname );
+    filename = strrchr( fullname, '\\' );
+    if( filename == NULL )
+    {
+        filename = strrchr( fullname, '/' );
+    }
+    if( filename == NULL )
+    {
+        filename = fullname;
+    }
+    else
+    {
+        filename++;
+    }
+
+    for( line = 1, error = 0, total = 0; total < num ;line++ )
+    {
+        int count;
+
+        error = ( fscanf( info, "%s %d", filename, &count ) != 2 );
+        if( !error )
+        {
+            src = cvLoadImage( fullname, 0 );
+            error = ( src == NULL );
+            if( error )
+            {
+
+#if CV_VERBOSE
+                fprintf( stderr, "Unable to open image: %s\n", fullname );
+#endif /* CV_VERBOSE */
+
+            }
+        }
+        for( i = 0; (i < count) && (total < num); i++, total++ )
+        {
+            error = ( fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4 );
+            if( error ) break;
+            cvSetImageROI( src, cvRect( x, y, width, height ) );
+            cvResize( src, sample, width >= sample->width &&
+                      height >= sample->height ? CV_INTER_AREA : CV_INTER_LINEAR );
+
+            if( showsamples )
+            {
+                cvShowImage( "Sample", sample );
+                if( cvWaitKey( 0 ) == 27 )
+                {
+                    showsamples = 0;
+                }
+            }
+            icvWriteVecSample( vec, sample );
+        }
+
+        if( src )
+        {
+            cvReleaseImage( &src );
+        }
+
+        if( error )
+        {
+
+#if CV_VERBOSE
+            fprintf( stderr, "%s(%d) : parse error", infoname, line );
+#endif /* CV_VERBOSE */
+
+            break;
+        }
+    }
+
+    if( sample )
+    {
+        cvReleaseImage( &sample );
+    }
+
+    fclose( vec );
+    fclose( info );
+
+    return total;
+}
+
+typedef struct CvVecFile
+{
+    FILE*  input;
+    int    count;
+    int    vecsize;
+    int    last;
+    short* vector;
+} CvVecFile;
+
+static
+int icvGetTraininDataFromVec( CvMat* img, void* userdata )
+{
+    uchar tmp = 0;
+    int r = 0;
+    int c = 0;
+
+    assert( img->rows * img->cols == ((CvVecFile*) userdata)->vecsize );
+
+    size_t elements_read = fread( &tmp, sizeof( tmp ), 1, ((CvVecFile*) userdata)->input );
+    CV_Assert(elements_read == 1);
+    elements_read = fread( ((CvVecFile*) userdata)->vector, sizeof( short ),
+           ((CvVecFile*) userdata)->vecsize, ((CvVecFile*) userdata)->input );
+    CV_Assert(elements_read == (size_t)((CvVecFile*) userdata)->vecsize);
+
+    if( feof( ((CvVecFile*) userdata)->input ) ||
+        (((CvVecFile*) userdata)->last)++ >= ((CvVecFile*) userdata)->count )
+    {
+        return 0;
+    }
+
+    for( r = 0; r < img->rows; r++ )
+    {
+        for( c = 0; c < img->cols; c++ )
+        {
+            CV_MAT_ELEM( *img, uchar, r, c ) =
+                (uchar) ( ((CvVecFile*) userdata)->vector[r * img->cols + c] );
+        }
+    }
+
+    return 1;
+}
+void cvShowVecSamples( const char* filename, int winwidth, int winheight,
+                       double scale )
+{
+    CvVecFile file;
+    short tmp;
+    int i;
+    CvMat* sample;
+
+    tmp = 0;
+    file.input = fopen( filename, "rb" );
+
+    if( file.input != NULL )
+    {
+        size_t elements_read1 = fread( &file.count, sizeof( file.count ), 1, file.input );
+        size_t elements_read2 = fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
+        size_t elements_read3 = fread( &tmp, sizeof( tmp ), 1, file.input );
+        size_t elements_read4 = fread( &tmp, sizeof( tmp ), 1, file.input );
+        CV_Assert(elements_read1 == 1 && elements_read2 == 1 && elements_read3 == 1 && elements_read4 == 1);
+
+        if( file.vecsize != winwidth * winheight )
+        {
+            int guessed_w = 0;
+            int guessed_h = 0;
+
+            fprintf( stderr, "Warning: specified sample width=%d and height=%d "
+                "does not correspond to .vec file vector size=%d.\n",
+                winwidth, winheight, file.vecsize );
+            if( file.vecsize > 0 )
+            {
+                guessed_w = cvFloor( sqrt( (float) file.vecsize ) );
+                if( guessed_w > 0 )
+                {
+                    guessed_h = file.vecsize / guessed_w;
+                }
+            }
+
+            if( guessed_w <= 0 || guessed_h <= 0 || guessed_w * guessed_h != file.vecsize)
+            {
+                fprintf( stderr, "Error: failed to guess sample width and height\n" );
+                fclose( file.input );
+
+                return;
+            }
+            else
+            {
+                winwidth = guessed_w;
+                winheight = guessed_h;
+                fprintf( stderr, "Guessed width=%d, guessed height=%d\n",
+                    winwidth, winheight );
+            }
+        }
+
+        if( !feof( file.input ) && scale > 0 )
+        {
+            CvMat* scaled_sample = 0;
+
+            file.last = 0;
+            file.vector = (short*) cvAlloc( sizeof( *file.vector ) * file.vecsize );
+            sample = scaled_sample = cvCreateMat( winheight, winwidth, CV_8UC1 );
+            if( scale != 1.0 )
+            {
+                scaled_sample = cvCreateMat( MAX( 1, cvCeil( scale * winheight ) ),
+                                             MAX( 1, cvCeil( scale * winwidth ) ),
+                                             CV_8UC1 );
+            }
+            cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
+            for( i = 0; i < file.count; i++ )
+            {
+                icvGetTraininDataFromVec( sample, &file );
+                if( scale != 1.0 ) cvResize( sample, scaled_sample, CV_INTER_LINEAR);
+                cvShowImage( "Sample", scaled_sample );
+                if( cvWaitKey( 0 ) == 27 ) break;
+            }
+            if( scaled_sample && scaled_sample != sample ) cvReleaseMat( &scaled_sample );
+            cvReleaseMat( &sample );
+            cvFree( &file.vector );
+        }
+        fclose( file.input );
+    }
+}
\ No newline at end of file
diff --git a/apps/createsamples/utility.hpp b/apps/createsamples/utility.hpp
new file mode 100644 (file)
index 0000000..9367778
--- /dev/null
@@ -0,0 +1,124 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including 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 __CREATESAMPLES_UTILITY_HPP__
+#define __CREATESAMPLES_UTILITY_HPP__
+
+#define CV_VERBOSE  1
+
+/*
+ * cvCreateTrainingSamples
+ *
+ * Create training samples applying random distortions to sample image and
+ * store them in .vec file
+ *
+ * filename        - .vec file name
+ * imgfilename     - sample image file name
+ * bgcolor         - background color for sample image
+ * bgthreshold     - background color threshold. Pixels those colors are in range
+ *   [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent
+ * bgfilename      - background description file name. If not NULL samples
+ *   will be put on arbitrary background
+ * count           - desired number of samples
+ * invert          - if not 0 sample foreground pixels will be inverted
+ *   if invert == CV_RANDOM_INVERT then samples will be inverted randomly
+ * maxintensitydev - desired max intensity deviation of foreground samples pixels
+ * maxxangle       - max rotation angles
+ * maxyangle
+ * maxzangle
+ * showsamples     - if not 0 samples will be shown
+ * winwidth        - desired samples width
+ * winheight       - desired samples height
+ */
+#define CV_RANDOM_INVERT 0x7FFFFFFF
+
+void cvCreateTrainingSamples( const char* filename,
+                              const char* imgfilename, int bgcolor, int bgthreshold,
+                              const char* bgfilename, int count,
+                              int invert = 0, int maxintensitydev = 40,
+                              double maxxangle = 1.1,
+                              double maxyangle = 1.1,
+                              double maxzangle = 0.5,
+                              int showsamples = 0,
+                              int winwidth = 24, int winheight = 24 );
+
+void cvCreateTestSamples( const char* infoname,
+                          const char* imgfilename, int bgcolor, int bgthreshold,
+                          const char* bgfilename, int count,
+                          int invert, int maxintensitydev,
+                          double maxxangle, double maxyangle, double maxzangle,
+                          int showsamples,
+                          int winwidth, int winheight );
+
+/*
+ * cvCreateTrainingSamplesFromInfo
+ *
+ * Create training samples from a set of marked up images and store them into .vec file
+ * infoname    - file in which marked up image descriptions are stored
+ * num         - desired number of samples
+ * showsamples - if not 0 samples will be shown
+ * winwidth    - sample width
+ * winheight   - sample height
+ *
+ * Return number of successfully created samples
+ */
+int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
+                                     int num,
+                                     int showsamples,
+                                     int winwidth, int winheight );
+
+/*
+ * cvShowVecSamples
+ *
+ * Shows samples stored in .vec file
+ *
+ * filename
+ *   .vec file name
+ * winwidth
+ *   sample width
+ * winheight
+ *   sample height
+ * scale
+ *   the scale each sample is adjusted to
+ */
+void cvShowVecSamples( const char* filename, int winwidth, int winheight, double scale );
+
+#endif //__CREATESAMPLES_UTILITY_HPP__