From c48f30d4ecdeaf80d17c939bc5ed9624855dfe6a Mon Sep 17 00:00:00 2001 From: vbystricky Date: Mon, 8 Dec 2014 17:53:14 +0400 Subject: [PATCH] Move createsamples application from 2.4 version --- apps/CMakeLists.txt | 1 + apps/createsamples/CMakeLists.txt | 39 + apps/createsamples/createsamples.cpp | 245 +++++ apps/createsamples/utility.cpp | 1681 ++++++++++++++++++++++++++++++++++ apps/createsamples/utility.hpp | 124 +++ 5 files changed, 2090 insertions(+) create mode 100644 apps/createsamples/CMakeLists.txt create mode 100644 apps/createsamples/createsamples.cpp create mode 100644 apps/createsamples/utility.cpp create mode 100644 apps/createsamples/utility.hpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 1814efb..e9783de 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -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 index 0000000..591a0b8 --- /dev/null +++ b/apps/createsamples/CMakeLists.txt @@ -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 index 0000000..9f05e41 --- /dev/null +++ b/apps/createsamples/createsamples.cpp @@ -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 +#include +#include +#include +#include + +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 ]\n" + " [-img ]\n" + " [-vec ]\n" + " [-bg ]\n [-num ]\n" + " [-bgcolor ]\n" + " [-inv] [-randinv] [-bgthresh ]\n" + " [-maxidev ]\n" + " [-maxxangle ]\n" + " [-maxyangle ]\n" + " [-maxzangle ]\n" + " [-show []]\n" + " [-w ]\n [-h ]\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 index 0000000..b5834f3 --- /dev/null +++ b/apps/createsamples/utility.cpp @@ -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 +#include + +#include +#include +#ifdef _WIN32 +#include +#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 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." ); + } + + /* is the index of the topmost quad vertice + if there are two such vertices 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 vertices in such way that they follow in a CW + direction and the first vertice is the topmost one and put them + into */ + 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, is the index of the rightmost one + otherwise */ + if( q[left][1] == q[left+1][1] ) + { + right = 1; + } + + /* follows in a CCW direction */ + next_left = 3; + /* follows 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 + * 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. + * and 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 index 0000000..9367778 --- /dev/null +++ b/apps/createsamples/utility.hpp @@ -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__ -- 2.7.4