diff --git a/modules/objdetect/CMakeLists.txt b/modules/objdetect/CMakeLists.txt index 995748a8c7..65f4795fdc 100644 --- a/modules/objdetect/CMakeLists.txt +++ b/modules/objdetect/CMakeLists.txt @@ -1 +1 @@ -define_opencv_module(objdetect opencv_core opencv_imgproc) +define_opencv_module(objdetect opencv_core opencv_imgproc opencv_highgui) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 78e8d3ffa8..c86a81cf90 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -139,6 +139,129 @@ CVAPI(void) cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascad CVAPI(int) cvRunHaarClassifierCascade( const CvHaarClassifierCascade* cascade, CvPoint pt, int start_stage CV_DEFAULT(0)); + +/****************************************************************************************\ +* Latent SVM Object Detection functions * +\****************************************************************************************/ + +// DataType: STRUCT position +// Structure describes the position of the filter in the feature pyramid +// l - level in the feature pyramid +// (x, y) - coordinate in level l +typedef struct +{ + unsigned int x; + unsigned int y; + unsigned int l; +} position; + +// DataType: STRUCT filterObject +// Description of the filter, which corresponds to the part of the object +// V - ideal (penalty = 0) position of the partial filter +// from the root filter position (V_i in the paper) +// penaltyFunction - vector describes penalty function (d_i in the paper) +// pf[0] * x + pf[1] * y + pf[2] * x^2 + pf[3] * y^2 +// FILTER DESCRIPTION +// Rectangular map (sizeX x sizeY), +// every cell stores feature vector (dimension = p) +// H - matrix of feature vectors +// to set and get feature vectors (i,j) +// used formula H[(j * sizeX + i) * p + k], where +// k - component of feature vector in cell (i, j) +// END OF FILTER DESCRIPTION +// xp - auxillary parameter for internal use +// size of row in feature vectors +// (yp = (int) (p / xp); p = xp * yp) +typedef struct{ + position V; + float fineFunction[4]; + unsigned int sizeX; + unsigned int sizeY; + unsigned int p; + unsigned int xp; + float *H; +} filterObject; + +// data type: STRUCT CvLatentSvmDetector +// structure contains internal representation of trained Latent SVM detector +// num_filters - total number of filters (root plus part) in model +// num_components - number of components in model +// num_part_filters - array containing number of part filters for each component +// filters - root and part filters for all model components +// b - biases for all model components +// score_threshold - confidence level threshold +typedef struct CvLatentSvmDetector +{ + int num_filters; + int num_components; + int* num_part_filters; + filterObject** filters; + float* b; + float score_threshold; +} +CvLatentSvmDetector; + +// data type: STRUCT CvObjectDetection +// structure contains the bounding box and confidence level for detected object +// rect - bounding box for a detected object +// score - confidence level +typedef struct CvObjectDetection +{ + CvRect rect; + float score; +} CvObjectDetection; + +//////////////// Object Detection using Latent SVM ////////////// + + +/* +// load trained detector from a file +// +// API +// CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename); +// INPUT +// filename - path to the file containing the parameters of + - trained Latent SVM detector +// OUTPUT +// trained Latent SVM detector in internal representation +*/ +CVAPI(CvLatentSvmDetector*) cvLoadLatentSvmDetector(const char* filename); + +/* +// release memory allocated for CvLatentSvmDetector structure +// +// API +// void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); +// INPUT +// detector - CvLatentSvmDetector structure to be released +// OUTPUT +*/ +CVAPI(void) cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); + +/* +// find rectangular regions in the given image that are likely +// to contain objects and corresponding confidence levels +// +// API +// CvSeq* cvLatentSvmDetectObjects(const IplImage* image, +// CvLatentSvmDetector* detector, +// CvMemStorage* storage, +// float overlap_threshold = 0.5f); +// INPUT +// image - image to detect objects in +// detector - Latent SVM detector in internal representation +// storage - memory storage to store the resultant sequence +// of the object candidate rectangles +// overlap_threshold - threshold for the non-maximum suppression algorithm + = 0.5f [here will be the reference to original paper] +// OUTPUT +// sequence of detected objects (bounding boxes and confidence levels stored in CvObjectDetection structures) +*/ +CVAPI(CvSeq*) cvLatentSvmDetectObjects(IplImage* image, + CvLatentSvmDetector* detector, + CvMemStorage* storage, + float overlap_threshold CV_DEFAULT(0.5f)); + #ifdef __cplusplus } diff --git a/modules/objdetect/src/_distancetransform.h b/modules/objdetect/src/_distancetransform.h new file mode 100644 index 0000000000..8000405113 --- /dev/null +++ b/modules/objdetect/src/_distancetransform.h @@ -0,0 +1,140 @@ +#ifndef DIST_TRANSFORM +#define DIST_TRANSFORM + +#include "precomp.hpp" +#include "_types.h" +#include "_error.h" + + +/* +// Computation the point of intersection functions +// (parabolas on the variable y) +// a(y - q1) + b(q1 - y)(q1 - y) + f[q1] +// a(y - q2) + b(q2 - y)(q2 - y) + f[q2] +// +// API +// int GetPointOfIntersection(const F_type *f, + const F_type a, const F_type b, + int q1, int q2, F_type *point); +// INPUT +// f - function on the regular grid +// a - coefficient of the function +// b - coefficient of the function +// q1 - parameter of the function +// q2 - parameter of the function +// OUTPUT +// point - point of intersection +// RESULT +// Error status +*/ +int GetPointOfIntersection(const float *f, + const float a, const float b, + int q1, int q2, float *point); + +/* +// Decision of one dimensional problem generalized distance transform +// on the regular grid at all points +// min (a(y' - y) + b(y' - y)(y' - y) + f(y')) (on y') +// +// API +// int DistanceTransformOneDimensionalProblem(const F_type *f, const int n, + const F_type a, const F_type b, + F_type *distanceTransform, + int *points); +// INPUT +// f - function on the regular grid +// n - grid dimension +// a - coefficient of optimizable function +// b - coefficient of optimizable function +// OUTPUT +// distanceTransform - values of generalized distance transform +// points - arguments that corresponds to the optimal value of function +// RESULT +// Error status +*/ +int DistanceTransformOneDimensionalProblem(const float *f, const int n, + const float a, const float b, + float *distanceTransform, + int *points); + +/* +// Computation next cycle element +// +// API +// int GetNextCycleElement(int k, int n, int q); +// INPUT +// k - index of the previous cycle element +// n - number of matrix rows +// q - parameter that equal (number_of_rows * number_of_columns - 1) +// OUTPUT +// None +// RESULT +// Next cycle element +*/ +int GetNextCycleElement(int k, int n, int q); + +/* +// Transposition of cycle elements +// +// API +// void TransposeCycleElements(F_type *a, int *cycle, int cycle_len); +// INPUT +// a - initial matrix +// cycle - cycle +// cycle_len - cycle length +// OUTPUT +// a - matrix with transposed elements +// RESULT +// None +*/ +void TransposeCycleElements(float *a, int *cycle, int cycle_len); + +/* +// Getting transposed matrix +// +// API +// void Transpose(F_type *a, int n, int m); +// INPUT +// a - initial matrix +// n - number of rows +// m - number of columns +// OUTPUT +// a - transposed matrix +// RESULT +// Error status +*/ +void Transpose(float *a, int n, int m); + +/* +// Decision of two dimensional problem generalized distance transform +// on the regular grid at all points +// min{d2(y' - y) + d4(y' - y)(y' - y) + + min(d1(x' - x) + d3(x' - x)(x' - x) + f(x',y'))} (on x', y') +// +// API +// int DistanceTransformTwoDimensionalProblem(const F_type *f, + const int n, const int m, + const F_type coeff[4], + F_type *distanceTransform, + int *pointsX, int *pointsY); +// INPUT +// f - function on the regular grid +// n - number of rows +// m - number of columns +// coeff - coefficients of optimizable function + coeff[0] = d1, coeff[1] = d2, + coeff[2] = d3, coeff[3] = d4 +// OUTPUT +// distanceTransform - values of generalized distance transform +// pointsX - arguments x' that correspond to the optimal value +// pointsY - arguments y' that correspond to the optimal value +// RESULT +// Error status +*/ +int DistanceTransformTwoDimensionalProblem(const float *f, + const int n, const int m, + const float coeff[4], + float *distanceTransform, + int *pointsX, int *pointsY); + +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_error.h b/modules/objdetect/src/_error.h new file mode 100644 index 0000000000..e783dfa14f --- /dev/null +++ b/modules/objdetect/src/_error.h @@ -0,0 +1,16 @@ +#ifndef SVM_ERROR +#define SVM_ERROR + +#define LATENT_SVM_OK 0 +#define DISTANCE_TRANSFORM_OK 1 +#define DISTANCE_TRANSFORM_GET_INTERSECTION_ERROR -1 +#define DISTANCE_TRANSFORM_ERROR -2 +#define DISTANCE_TRANSFORM_EQUAL_POINTS -3 +#define LATENT_SVM_GET_FEATURE_PYRAMID_FAILED -4 +#define LATENT_SVM_SEARCH_OBJECT_FAILED -5 +#define LATENT_SVM_FAILED_SUPERPOSITION -6 +#define FILTER_OUT_OF_BOUNDARIES -7 +#define FFT_OK 2 +#define FFT_ERROR -8 + +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_fft.h b/modules/objdetect/src/_fft.h new file mode 100644 index 0000000000..a2d15d4cc4 --- /dev/null +++ b/modules/objdetect/src/_fft.h @@ -0,0 +1,81 @@ +#ifndef _FFT_H +#define _FFT_H + +#include "precomp.hpp" +#include "_types.h" +#include "_error.h" + +#include + +/* +// 1-dimensional FFT +// +// API +// int fft(float *x_in, float *x_out, int n, int shift); +// INPUT +// x_in - input signal +// n - number of elements for searching Fourier image +// shift - shift between input elements +// OUTPUT +// x_out - output signal (contains 2n elements in order + Re(x_in[0]), Im(x_in[0]), Re(x_in[1]), Im(x_in[1]) and etc.) +// RESULT +// Error status +*/ +int fft(float *x_in, float *x_out, int n, int shift); + +/* +// Inverse 1-dimensional FFT +// +// API +// int fftInverse(float *x_in, float *x_out, int n, int shift); +// INPUT +// x_in - Fourier image of 1d input signal(contains 2n elements + in order Re(x_in[0]), Im(x_in[0]), + Re(x_in[1]), Im(x_in[1]) and etc.) +// n - number of elements for searching counter FFT image +// shift - shift between input elements +// OUTPUT +// x_in - input signal (contains n elements) +// RESULT +// Error status +*/ +int fftInverse(float *x_in, float *x_out, int n, int shift); + +/* +// 2-dimensional FFT +// +// API +// int fft2d(float *x_in, float *x_out, int numRows, int numColls); +// INPUT +// x_in - input signal (matrix, launched by rows) +// numRows - number of rows +// numColls - number of collumns +// OUTPUT +// x_out - output signal (contains (2 * numRows * numColls) elements + in order Re(x_in[0][0]), Im(x_in[0][0]), + Re(x_in[0][1]), Im(x_in[0][1]) and etc.) +// RESULT +// Error status +*/ +int fft2d(float *x_in, float *x_out, int numRows, int numColls); + +/* +// Inverse 2-dimensional FFT +// +// API +// int fftInverse2d(float *x_in, float *x_out, int numRows, int numColls); +// INPUT +// x_in - Fourier image of matrix (contains (2 * numRows * numColls) + elements in order Re(x_in[0][0]), Im(x_in[0][0]), + Re(x_in[0][1]), Im(x_in[0][1]) and etc.) +// numRows - number of rows +// numColls - number of collumns +// OUTPUT +// x_out - initial signal (matrix, launched by rows) +// RESULT +// Error status +*/ +int fftInverse2d(float *x_in, float *x_out, int numRows, int numColls); + +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_latentsvm.h b/modules/objdetect/src/_latentsvm.h new file mode 100644 index 0000000000..7bf4a11b1f --- /dev/null +++ b/modules/objdetect/src/_latentsvm.h @@ -0,0 +1,401 @@ +/*****************************************************************************/ +/* Latent SVM prediction API */ +/*****************************************************************************/ + +#ifndef SVM_LATENTSVM +#define SVM_LATENTSVM + +#include +#include "precomp.hpp" +#include "_types.h" +#include "_error.h" +#include "_routine.h" + +////////////////////////////////////////////////////////////// +// Building feature pyramid +// (pyramid constructed both contrast and non-contrast image) +////////////////////////////////////////////////////////////// + +/* +// Getting feature pyramid +// +// API +// int getFeaturePyramid(IplImage * image, const filterObject **all_F, + const int n_f, + const int lambda, const int k, + const int startX, const int startY, + const int W, const int H, featurePyramid **maps); +// INPUT +// image - image +// lambda - resize scale +// k - size of cells +// startX - X coordinate of the image rectangle to search +// startY - Y coordinate of the image rectangle to search +// W - width of the image rectangle to search +// H - height of the image rectangle to search +// OUTPUT +// maps - feature maps for all levels +// RESULT +// Error status +*/ +int getFeaturePyramid(IplImage * image, + const int lambda, const int k, + const int startX, const int startY, + const int W, const int H, featurePyramid **maps); + +/* +// Getting feature map for the selected subimage +// +// API +// int getFeatureMaps(const IplImage * image, const int k, featureMap **map); +// INPUT +// image - selected subimage +// k - size of cells +// OUTPUT +// map - feature map +// RESULT +// Error status +*/ +int getFeatureMaps_dp(const IplImage * image, const int k, featureMap **map); + + +/* +// Feature map Normalization and Truncation +// +// API +// int normalizationAndTruncationFeatureMaps(featureMap *map, const float alfa); +// INPUT +// map - feature map +// alfa - truncation threshold +// OUTPUT +// map - truncated and normalized feature map +// RESULT +// Error status +*/ +int normalizationAndTruncationFeatureMaps(featureMap *map, const float alfa); + +/* +// Feature map reduction +// In each cell we reduce dimension of the feature vector +// according to original paper special procedure +// +// API +// int PCAFeatureMaps(featureMap *map) +// INPUT +// map - feature map +// OUTPUT +// map - feature map +// RESULT +// Error status +*/ +int PCAFeatureMaps(featureMap *map); + +////////////////////////////////////////////////////////////// +// search object +////////////////////////////////////////////////////////////// + +/* +// Transformation filter displacement from the block space +// to the space of pixels at the initial image +// +// API +// int convertPoints(int countLevel, int lambda, + int initialImageLevel, + CvPoint *points, int *levels, + CvPoint **partsDisplacement, int kPoints, int n, + int maxXBorder, + int maxYBorder); +// INPUT +// countLevel - the number of levels in the feature pyramid +// lambda - method parameter +// initialImageLevel - level of feature pyramid that contains feature map + for initial image +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// partsDisplacement - displacement of part filters (in the block space) +// kPoints - number of root filter positions +// n - number of part filters +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// points - the set of root filter positions (in the space of pixels) +// partsDisplacement - displacement of part filters (in the space of pixels) +// RESULT +// Error status +*/ +int convertPoints(int countLevel, int lambda, + int initialImageLevel, + CvPoint *points, int *levels, + CvPoint **partsDisplacement, int kPoints, int n, + int maxXBorder, + int maxYBorder); + +/* +// Elimination boxes that are outside the image boudaries +// +// API +// int clippingBoxes(int width, int height, + CvPoint *points, int kPoints); +// INPUT +// width - image wediht +// height - image heigth +// points - a set of points (coordinates of top left or + bottom right corners) +// kPoints - points number +// OUTPUT +// points - updated points (if coordinates less than zero then + set zero coordinate, if coordinates more than image + size then set coordinates equal image size) +// RESULT +// Error status +*/ +#ifdef __cplusplus +extern "C" +#endif +int clippingBoxes(int width, int height, + CvPoint *points, int kPoints); + +/* +// Creation feature pyramid with nullable border +// +// API +// featurePyramid* createFeaturePyramidWithBorder(const IplImage *image, + int maxXBorder, int maxYBorder); + +// INPUT +// image - initial image +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// RESULT +// Feature pyramid with nullable border +*/ +#ifdef __cplusplus +extern "C" +#endif +featurePyramid* createFeaturePyramidWithBorder(IplImage *image, + int maxXBorder, int maxYBorder); + +/* +// Computation of the root filter displacement and values of score function +// +// API +// int searchObject(const featurePyramid *H, const filterObject **all_F, int n, + float b, + int maxXBorder, + int maxYBorder, + CvPoint **points, int **levels, int *kPoints, float *score, + CvPoint ***partsDisplacement); +// INPUT +// H - feature pyramid +// all_F - the set of filters (the first element is root filter, + other elements - part filters) +// n - the number of part filters +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// points - positions (x, y) of the upper-left corner + of root filter frame +// levels - levels that correspond to each position +// kPoints - number of positions +// score - value of the score function +// partsDisplacement - part filters displacement for each position + of the root filter +// RESULT +// Error status +*/ +int searchObject(const featurePyramid *H, const filterObject **all_F, int n, + float b, + int maxXBorder, + int maxYBorder, + CvPoint **points, int **levels, int *kPoints, float *score, + CvPoint ***partsDisplacement); + +/* +// Computation of the root filter displacement and values of score function +// +// API +// int searchObjectThreshold(const featurePyramid *H, + const filterObject **all_F, int n, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + CvPoint **points, int **levels, int *kPoints, + float **score, CvPoint ***partsDisplacement); +// INPUT +// H - feature pyramid +// all_F - the set of filters (the first element is root filter, + other elements - part filters) +// n - the number of part filters +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// points - positions (x, y) of the upper-left corner + of root filter frame +// levels - levels that correspond to each position +// kPoints - number of positions +// score - values of the score function +// partsDisplacement - part filters displacement for each position + of the root filter +// RESULT +// Error status +*/ +int searchObjectThreshold(const featurePyramid *H, + const filterObject **all_F, int n, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + CvPoint **points, int **levels, int *kPoints, + float **score, CvPoint ***partsDisplacement); + +/* +// Computation root filters displacement and values of score function +// +// API +// int searchObjectThresholdSomeComponents(const featurePyramid *H, + const filterObject **filters, + int kComponents, const int *kPartFilters, + const float *b, float scoreThreshold, + CvPoint **points, CvPoint **oppPoints, + float **score, int *kPoints); +// INPUT +// H - feature pyramid +// filters - filters (root filter then it's part filters, etc.) +// kComponents - root filters number +// kPartFilters - array of part filters number for each component +// b - array of linear terms +// scoreThreshold - score threshold +// OUTPUT +// points - root filters displacement (top left corners) +// oppPoints - root filters displacement (bottom right corners) +// score - array of score values +// kPoints - number of boxes +// RESULT +// Error status +*/ +#ifdef __cplusplus +extern "C" +#endif +int searchObjectThresholdSomeComponents(const featurePyramid *H, + const filterObject **filters, + int kComponents, const int *kPartFilters, + const float *b, float scoreThreshold, + CvPoint **points, CvPoint **oppPoints, + float **score, int *kPoints); + +/* +// Compute opposite point for filter box +// +// API +// int getOppositePoint(CvPoint point, + int sizeX, int sizeY, + float step, int degree, + CvPoint *oppositePoint); + +// INPUT +// point - coordinates of filter top left corner + (in the space of pixels) +// (sizeX, sizeY) - filter dimension in the block space +// step - scaling factor +// degree - degree of the scaling factor +// OUTPUT +// oppositePoint - coordinates of filter bottom corner + (in the space of pixels) +// RESULT +// Error status +*/ +int getOppositePoint(CvPoint point, + int sizeX, int sizeY, + float step, int degree, + CvPoint *oppositePoint); + +/* +// Drawing root filter boxes +// +// API +// int showRootFilterBoxes(const IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); +// INPUT +// image - initial image +// filter - root filter object +// points - a set of points +// levels - levels of feature pyramid +// kPoints - number of points +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// window contained initial image and filter boxes +// RESULT +// Error status +*/ +int showRootFilterBoxes(IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); + +/* +// Drawing part filter boxes +// +// API +// int showPartFilterBoxes(const IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); +// INPUT +// image - initial image +// filters - a set of part filters +// n - number of part filters +// partsDisplacement - a set of points +// levels - levels of feature pyramid +// kPoints - number of foot filter positions +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// window contained initial image and filter boxes +// RESULT +// Error status +*/ +int showPartFilterBoxes(IplImage *image, + const filterObject **filters, + int n, CvPoint **partsDisplacement, + int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); + +/* +// Drawing boxes +// +// API +// int showBoxes(const IplImage *img, + const CvPoint *points, const CvPoint *oppositePoints, int kPoints, + CvScalar color, int thickness, int line_type, int shift); +// INPUT +// img - initial image +// points - top left corner coordinates +// oppositePoints - right bottom corner coordinates +// kPoints - points number +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// RESULT +// Error status +*/ +int showBoxes(IplImage *img, + const CvPoint *points, const CvPoint *oppositePoints, int kPoints, + CvScalar color, int thickness, int line_type, int shift); + +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_lsvmparser.h b/modules/objdetect/src/_lsvmparser.h new file mode 100644 index 0000000000..3d5cf56ffc --- /dev/null +++ b/modules/objdetect/src/_lsvmparser.h @@ -0,0 +1,66 @@ +#ifndef LSVM_PARSER +#define LSVM_PARSER + +#include "precomp.hpp" +#include "_types.h" + +#define MODEL 1 +#define P 2 +#define COMP 3 +#define SCORE 4 +#define RFILTER 100 +#define PFILTERs 101 +#define PFILTER 200 +#define SIZEX 150 +#define SIZEY 151 +#define WEIGHTS 152 +#define TAGV 300 +#define Vx 350 +#define Vy 351 +#define TAGD 400 +#define Dx 451 +#define Dy 452 +#define Dxx 453 +#define Dyy 454 +#define BTAG 500 + +#define STEP_END 1000 + +#define EMODEL (STEP_END + MODEL) +#define EP (STEP_END + P) +#define ECOMP (STEP_END + COMP) +#define ESCORE (STEP_END + SCORE) +#define ERFILTER (STEP_END + RFILTER) +#define EPFILTERs (STEP_END + PFILTERs) +#define EPFILTER (STEP_END + PFILTER) +#define ESIZEX (STEP_END + SIZEX) +#define ESIZEY (STEP_END + SIZEY) +#define EWEIGHTS (STEP_END + WEIGHTS) +#define ETAGV (STEP_END + TAGV) +#define EVx (STEP_END + Vx) +#define EVy (STEP_END + Vy) +#define ETAGD (STEP_END + TAGD) +#define EDx (STEP_END + Dx) +#define EDy (STEP_END + Dy) +#define EDxx (STEP_END + Dxx) +#define EDyy (STEP_END + Dyy) +#define EBTAG (STEP_END + BTAG) + +//extern "C" { + void LSVMparser(const char * filename, filterObject *** model, int *last, int *max, int **comp, float **b, int *count, float * score); +#ifdef __cplusplus +extern "C" +#endif + int loadModel( + // Входные параметры + const char *modelPath,// - путь до файла с моделью + + // Выходные параметры + filterObject ***filters,// - массив указателей на фильтры компонент + int *kFilters, //- общее количество фильтров во всех моделях + int *kComponents, //- количество компонент + int **kPartFilters, //- массив, содержащий количество точных фильтров в каждой компоненте + float **b, //- массив линейных членов в оценочной функции + float *scoreThreshold); //- порог для score) +//}; +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_matching.h b/modules/objdetect/src/_matching.h new file mode 100644 index 0000000000..266ddf6232 --- /dev/null +++ b/modules/objdetect/src/_matching.h @@ -0,0 +1,396 @@ +/*****************************************************************************/ +/* Matching procedure API */ +/*****************************************************************************/ +// +#ifndef SVM_MATCHING +#define SVM_MATCHING + +#include "_latentsvm.h" +#include "_error.h" +#include "_distancetransform.h" +#include "_fft.h" +#include "_routine.h" + +//extern "C" { +/* +// Function for convolution computation +// +// API +// int convolution(const filterObject *Fi, const featureMap *map, float *f); +// INPUT +// Fi - filter object +// map - feature map +// OUTPUT +// f - the convolution +// RESULT +// Error status +*/ +int convolution(const filterObject *Fi, const featureMap *map, float *f); + +/* +// Computation multiplication of FFT images +// +// API +// int fftImagesMulti(float *fftImage1, float *fftImage2, int numRows, int numColls, + float *multi); +// INPUT +// fftImage1 - first fft image +// fftImage2 - second fft image +// (numRows, numColls) - image dimesions +// OUTPUT +// multi - multiplication +// RESULT +// Error status +*/ +int fftImagesMulti(float *fftImage1, float *fftImage2, int numRows, int numColls, + float *multi); + +/* +// Turnover filter matrix for the single feature +// +// API +// int rot2PI(float *filter, int dimX, int dimY, float *rot2PIFilter, + int p, int shift); +// INPUT +// filter - filter weight matrix +// (dimX, dimY) - dimension of filter matrix +// p - number of features +// shift - number of feature (or channel) +// OUTPUT +// rot2PIFilter - rotated matrix +// RESULT +// Error status +*/ +int rot2PI(float *filter, int dimX, int dimY, float *rot2PIFilter, + int p, int shift); + +/* +// Addition nullable bars to the dimension of feature map (single feature) +// +// API +// int addNullableBars(float *rot2PIFilter, int dimX, int dimY, + float *newFilter, int newDimX, int newDimY); +// INPUT +// rot2PIFilter - filter matrix for the single feature that was rotated +// (dimX, dimY) - dimension rot2PIFilter +// (newDimX, newDimY)- dimension of feature map for the single feature +// OUTPUT +// newFilter - filter matrix with nullable bars +// RESULT +// Error status +*/ +int addNullableBars(float *rot2PIFilter, int dimX, int dimY, + float *newFilter, int newDimX, int newDimY); + +/* +// Computation FFT image for filter object +// +// API +// int getFFTImageFilterObject(const filterObject *filter, + int mapDimX, int mapDimY, + fftImage **image); +// INPUT +// filter - filter object +// (mapDimX, mapDimY)- dimension of feature map +// OUTPUT +// image - fft image +// RESULT +// Error status +*/ +int getFFTImageFilterObject(const filterObject *filter, + int mapDimX, int mapDimY, + fftImage **image); + +/* +// Computation FFT image for feature map +// +// API +// int getFFTImageFeatureMap(const featureMap *map, fftImage **image); +// INPUT +// OUTPUT +// RESULT +// Error status +*/ +int getFFTImageFeatureMap(const featureMap *map, fftImage **image); + +/* +// Function for convolution computation using FFT +// +// API +// int convFFTConv2d(const fftImage *featMapImage, const fftImage *filterImage, + int filterDimX, int filterDimY, float **conv); +// INPUT +// featMapImage - feature map image +// filterImage - filter image +// (filterDimX,filterDimY) - filter dimension +// OUTPUT +// conv - the convolution +// RESULT +// Error status +*/ +int convFFTConv2d(const fftImage *featMapImage, const fftImage *filterImage, + int filterDimX, int filterDimY, float **conv); + +/* +// Computation objective function D according the original paper +// +// API +// int filterDispositionLevel(const filterObject *Fi, const featureMap *pyramid, + float **scoreFi, + int **pointsX, int **pointsY); +// INPUT +// Fi - filter object (weights and coefficients of penalty + function that are used in this routine) +// pyramid - feature map +// OUTPUT +// scoreFi - values of distance transform on the level at all positions +// (pointsX, pointsY)- positions that correspond to the maximum value + of distance transform at all grid nodes +// RESULT +// Error status +*/ +int filterDispositionLevel(const filterObject *Fi, const featureMap *pyramid, + float **scoreFi, + int **pointsX, int **pointsY); + +/* +// Computation objective function D according the original paper using FFT +// +// API +// int filterDispositionLevelFFT(const filterObject *Fi, const fftImage *featMapImage, + float **scoreFi, + int **pointsX, int **pointsY); +// INPUT +// Fi - filter object (weights and coefficients of penalty + function that are used in this routine) +// featMapImage - FFT image of feature map +// OUTPUT +// scoreFi - values of distance transform on the level at all positions +// (pointsX, pointsY)- positions that correspond to the maximum value + of distance transform at all grid nodes +// RESULT +// Error status +*/ +int filterDispositionLevelFFT(const filterObject *Fi, const fftImage *featMapImage, + float **scoreFi, + int **pointsX, int **pointsY); + +/* +// Computation border size for feature map +// +// API +// int computeBorderSize(int maxXBorder, int maxYBorder, int *bx, int *by); +// INPUT +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// bx - border size (X-direction) +// by - border size (Y-direction) +// RESULT +// Error status +*/ +int computeBorderSize(int maxXBorder, int maxYBorder, int *bx, int *by); + +/* +// Addition nullable border to the feature map +// +// API +// int addNullableBorder(featureMap *map, int bx, int by); +// INPUT +// map - feature map +// bx - border size (X-direction) +// by - border size (Y-direction) +// OUTPUT +// RESULT +// Error status +*/ +int addNullableBorder(featureMap *map, int bx, int by); + +/* +// Computation the maximum of the score function at the level +// +// API +// int maxFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float *score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// level - feature pyramid level for computation maximum score +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// score - the maximum of the score function at the level +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int maxFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float *score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); + +/* +// Computation score function at the level that exceed threshold +// +// API +// int thresholdFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// level - feature pyramid level for computation maximum score +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// score - score function at the level that exceed threshold +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int thresholdFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); + +/* +// Computation the maximum of the score function +// +// API +// int maxFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, float b, + int maxXBorder, int maxYBorder, + float *score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// score - the maximum of the score function +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int maxFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, float b, + int maxXBorder, int maxYBorder, + float *score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); + +/* +// Computation score function that exceed threshold +// +// API +// int thresholdFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// score - score function values that exceed threshold +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int thresholdFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); + + +/* +// Perform non-maximum suppression algorithm (described in original paper) +// to remove "similar" bounding boxes +// +// API +// int nonMaximumSuppression(int numBoxes, const CvPoint *points, + const CvPoint *oppositePoints, const float *score, + float overlapThreshold, + int *numBoxesout, CvPoint **pointsOut, + CvPoint **oppositePointsOut, float **scoreOut); +// INPUT +// numBoxes - number of bounding boxes +// points - array of left top corner coordinates +// oppositePoints - array of right bottom corner coordinates +// score - array of detection scores +// overlapThreshold - threshold: bounding box is removed if overlap part + is greater than passed value +// OUTPUT +// numBoxesOut - the number of bounding boxes algorithm returns +// pointsOut - array of left top corner coordinates +// oppositePointsOut - array of right bottom corner coordinates +// scoreOut - array of detection scores +// RESULT +// Error status +*/ +#ifdef __cplusplus +extern "C" +#endif +int nonMaximumSuppression(int numBoxes, const CvPoint *points, + const CvPoint *oppositePoints, const float *score, + float overlapThreshold, + int *numBoxesOut, CvPoint **pointsOut, + CvPoint **oppositePointsOut, float **scoreOut); +#ifdef __cplusplus +extern "C" +#endif +int getMaxFilterDims(const filterObject **filters, int kComponents, + const int *kPartFilters, + unsigned int *maxXBorder, unsigned int *maxYBorder); +//} +#endif diff --git a/modules/objdetect/src/_resizeimg.h b/modules/objdetect/src/_resizeimg.h new file mode 100644 index 0000000000..b9dcd4c04f --- /dev/null +++ b/modules/objdetect/src/_resizeimg.h @@ -0,0 +1,11 @@ +#ifndef RESIZEIMG +#define RESIZEIMG + +#include "precomp.hpp" +#include "_types.h" + +IplImage * resize_opencv (IplImage * img, float scale); +IplImage * resize_article_dp1(IplImage * img, float scale, const int k); +IplImage * resize_article_dp(IplImage * img, float scale, const int k); + +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_routine.h b/modules/objdetect/src/_routine.h new file mode 100644 index 0000000000..866c359099 --- /dev/null +++ b/modules/objdetect/src/_routine.h @@ -0,0 +1,36 @@ +#ifndef _ROUTINE_H +#define _ROUTINE_H + +#include "precomp.hpp" +#include "_types.h" +#include "_error.h" + + +////////////////////////////////////////////////////////////// +// Memory management routines +// All paramaters names correspond to previous data structures description +// All "alloc" functions return allocated memory for 1 object +// with all fields including arrays +// Error status is return value +////////////////////////////////////////////////////////////// +int allocFilterObject(filterObject **obj, const int sizeX, const int sizeY, + const int p, const int xp); +int freeFilterObject (filterObject **obj); + +int allocFeatureMapObject(featureMap **obj, const int sizeX, const int sizeY, + const int p, const int xp); +int freeFeatureMapObject (featureMap **obj); + +#ifdef __cplusplus +extern "C" +#endif +int allocFeaturePyramidObject(featurePyramid **obj, + const int lambda, const int countLevel); + +#ifdef __cplusplus +extern "C" +#endif +int freeFeaturePyramidObject (featurePyramid **obj); +int allocFFTImage(fftImage **image, int p, int dimX, int dimY); +int freeFFTImage(fftImage **image); +#endif \ No newline at end of file diff --git a/modules/objdetect/src/_types.h b/modules/objdetect/src/_types.h new file mode 100644 index 0000000000..156d7d0e69 --- /dev/null +++ b/modules/objdetect/src/_types.h @@ -0,0 +1,93 @@ +#ifndef SVM_TYPE +#define SVM_TYPE + +//#include "opencv2/core/core.hpp" +//#include "opencv2/highgui/highgui.hpp" +#include "precomp.hpp" + +//#define FFT_CONV + +// Значение числа PI +#define PI 3.1415926535897932384626433832795 + +// Точность сравнения пары вещественных чисел +#define EPS 0.000001 + +// Минимальное и максимальное значение для вещественного типа данных +#define F_MAX 3.402823466e+38 +#define F_MIN -3.402823465e+38 + +// The number of elements in bin +// The number of sectors in gradient histogram building +#define CNTPARTION 9 + +// The number of levels in image resize procedure +// We need Lambda levels to resize image twice +#define LAMBDA 10 + +// Block size. Used in feature pyramid building procedure +#define SIDE_LENGTH 8 + +////////////////////////////////////////////////////////////// +// main data structures // +////////////////////////////////////////////////////////////// + +// DataType: STRUCT featureMap +// FEATURE MAP DESCRIPTION +// Rectangular map (sizeX x sizeY), +// every cell stores feature vector (dimension = p) +// H - matrix of feature vectors +// to set and get feature vectors (i,j) +// used formula Map[(j * sizeX + i) * p + k], where +// k - component of feature vector in cell (i, j) +// END OF FEATURE MAP DESCRIPTION +// xp - auxillary parameter for internal use +// size of row in feature vectors +// (yp = (int) (p / xp); p = xp * yp) +typedef struct{ + int sizeX; + int sizeY; + int p; + int xp; + float *Map; +} featureMap; + +// DataType: STRUCT featurePyramid +// +// countLevel - number of levels in the feature pyramid +// lambda - resize scale coefficient +// pyramid - array of pointers to feature map at different levels +typedef struct{ + int countLevel; + int lambda; + featureMap **pyramid; +} featurePyramid; + +// DataType: STRUCT filterDisposition +// The structure stores preliminary results in optimization process +// with objective function D +// +// x - array with X coordinates of optimization problems solutions +// y - array with Y coordinates of optimization problems solutions +// score - array with optimal objective values +typedef struct{ + float *score; + int *x; + int *y; +} filterDisposition; + +// DataType: STRUCT fftImage +// The structure stores FFT image +// +// p - number of channels +// x - array of FFT images for 2d signals +// n - number of rows +// m - number of collums +typedef struct{ + unsigned int p; + unsigned int dimX; + unsigned int dimY; + float **channels; +} fftImage; + +#endif diff --git a/modules/objdetect/src/distancetransform.cpp b/modules/objdetect/src/distancetransform.cpp new file mode 100644 index 0000000000..89c5749514 --- /dev/null +++ b/modules/objdetect/src/distancetransform.cpp @@ -0,0 +1,395 @@ +#include "_distancetransform.h" + +/* +// Computation the point of intersection functions +// (parabolas on the variable y) +// a(y - q1) + b(q1 - y)(q1 - y) + f[q1] +// a(y - q2) + b(q2 - y)(q2 - y) + f[q2] +// +// API +// int GetPointOfIntersection(const float *f, + const float a, const float b, + int q1, int q2, float *point); +// INPUT +// f - function on the regular grid +// a - coefficient of the function +// b - coefficient of the function +// q1 - parameter of the function +// q2 - parameter of the function +// OUTPUT +// point - point of intersection +// RESULT +// Error status +*/ +int GetPointOfIntersection(const float *f, + const float a, const float b, + int q1, int q2, float *point) +{ + if (q1 == q2) + { + return DISTANCE_TRANSFORM_EQUAL_POINTS; + } /* if (q1 == q2) */ + (*point) = ( (f[q2] - a * q2 + b *q2 * q2) - + (f[q1] - a * q1 + b * q1 * q1) ) / (2 * b * (q2 - q1)); + return DISTANCE_TRANSFORM_OK; +} + +/* +// Decision of one dimensional problem generalized distance transform +// on the regular grid at all points +// min (a(y' - y) + b(y' - y)(y' - y) + f(y')) (on y') +// +// API +// int DistanceTransformOneDimensionalProblem(const float *f, const int n, + const float a, const float b, + float *distanceTransform, + int *points); +// INPUT +// f - function on the regular grid +// n - grid dimension +// a - coefficient of optimizable function +// b - coefficient of optimizable function +// OUTPUT +// distanceTransform - values of generalized distance transform +// points - arguments that corresponds to the optimal value of function +// RESULT +// Error status +*/ +int DistanceTransformOneDimensionalProblem(const float *f, const int n, + const float a, const float b, + float *distanceTransform, + int *points) +{ + int i, k; + int tmp; + int diff; + float pointIntersection; + int *v; + float *z; + k = 0; + + // Allocation memory (must be free in this function) + v = (int *)malloc (sizeof(int) * n); + z = (float *)malloc (sizeof(float) * (n + 1)); + + v[0] = 0; + z[0] = (float)F_MIN; // left border of envelope + z[1] = (float)F_MAX; // right border of envelope + + for (i = 1; i < n; i++) + { + tmp = GetPointOfIntersection(f, a, b, v[k], i, &pointIntersection); + if (tmp != DISTANCE_TRANSFORM_OK) + { + free(v); + free(z); + return DISTANCE_TRANSFORM_GET_INTERSECTION_ERROR; + } /* if (tmp != DISTANCE_TRANSFORM_OK) */ + if (pointIntersection <= z[k]) + { + // Envelope doesn't contain current parabola + do + { + k--; + tmp = GetPointOfIntersection(f, a, b, v[k], i, &pointIntersection); + if (tmp != DISTANCE_TRANSFORM_OK) + { + free(v); + free(z); + return DISTANCE_TRANSFORM_GET_INTERSECTION_ERROR; + } /* if (tmp != DISTANCE_TRANSFORM_OK) */ + }while (pointIntersection <= z[k]); + // Addition parabola to the envelope + k++; + v[k] = i; + z[k] = pointIntersection; + z[k + 1] = (float)F_MAX; + } + else + { + // Addition parabola to the envelope + k++; + v[k] = i; + z[k] = pointIntersection; + z[k + 1] = (float)F_MAX; + } /* if (pointIntersection <= z[k]) */ + } + + // Computation values of generalized distance transform at all grid points + k = 0; + for (i = 0; i < n; i++) + { + while (z[k + 1] < i) + { + k++; + } + points[i] = v[k]; + diff = i - v[k]; + distanceTransform[i] = a * diff + b * diff * diff + f[v[k]]; + } + + // Release allocated memory + free(v); + free(z); + return DISTANCE_TRANSFORM_OK; +} + +/* +// Computation next cycle element +// +// API +// int GetNextCycleElement(int k, int n, int q); +// INPUT +// k - index of the previous cycle element +// n - number of matrix rows +// q - parameter that equal + (number_of_rows * number_of_columns - 1) +// OUTPUT +// None +// RESULT +// Next cycle element +*/ +int GetNextCycleElement(int k, int n, int q) +{ + return ((k * n) % q); +} + +/* +// Transpose cycle elements +// +// API +// void TransposeCycleElements(float *a, int *cycle, int cycle_len) +// INPUT +// a - initial matrix +// cycle - indeces array of cycle +// cycle_len - number of elements in the cycle +// OUTPUT +// a - matrix with transposed elements +// RESULT +// Error status +*/ +void TransposeCycleElements(float *a, int *cycle, int cycle_len) +{ + int i; + float buf; + for (i = cycle_len - 1; i > 0 ; i--) + { + buf = a[ cycle[i] ]; + a[ cycle[i] ] = a[ cycle[i - 1] ]; + a[ cycle[i - 1] ] = buf; + } +} + +/* +// Transpose cycle elements +// +// API +// void TransposeCycleElements(int *a, int *cycle, int cycle_len) +// INPUT +// a - initial matrix +// cycle - indeces array of cycle +// cycle_len - number of elements in the cycle +// OUTPUT +// a - matrix with transposed elements +// RESULT +// Error status +*/ +void TransposeCycleElements_int(int *a, int *cycle, int cycle_len) +{ + int i; + int buf; + for (i = cycle_len - 1; i > 0 ; i--) + { + buf = a[ cycle[i] ]; + a[ cycle[i] ] = a[ cycle[i - 1] ]; + a[ cycle[i - 1] ] = buf; + } +} + +/* +// Getting transposed matrix +// +// API +// void Transpose(float *a, int n, int m); +// INPUT +// a - initial matrix +// n - number of rows +// m - number of columns +// OUTPUT +// a - transposed matrix +// RESULT +// None +*/ +void Transpose(float *a, int n, int m) +{ + int *cycle; + int i, k, q, cycle_len; + int max_cycle_len; + + max_cycle_len = n * m; + + // Allocation memory (must be free in this function) + cycle = (int *)malloc(sizeof(int) * max_cycle_len); + + cycle_len = 0; + q = n * m - 1; + for (i = 1; i < q; i++) + { + k = GetNextCycleElement(i, n, q); + cycle[cycle_len] = i; + cycle_len++; + + while (k > i) + { + cycle[cycle_len] = k; + cycle_len++; + k = GetNextCycleElement(k, n, q); + } + if (k == i) + { + TransposeCycleElements(a, cycle, cycle_len); + } /* if (k == i) */ + cycle_len = 0; + } + + // Release allocated memory + free(cycle); +} + +/* +// Getting transposed matrix +// +// API +// void Transpose_int(int *a, int n, int m); +// INPUT +// a - initial matrix +// n - number of rows +// m - number of columns +// OUTPUT +// a - transposed matrix +// RESULT +// None +*/ +void Transpose_int(int *a, int n, int m) +{ + int *cycle; + int i, k, q, cycle_len; + int max_cycle_len; + + max_cycle_len = n * m; + + // Allocation memory (must be free in this function) + cycle = (int *)malloc(sizeof(int) * max_cycle_len); + + cycle_len = 0; + q = n * m - 1; + for (i = 1; i < q; i++) + { + k = GetNextCycleElement(i, n, q); + cycle[cycle_len] = i; + cycle_len++; + + while (k > i) + { + cycle[cycle_len] = k; + cycle_len++; + k = GetNextCycleElement(k, n, q); + } + if (k == i) + { + TransposeCycleElements_int(a, cycle, cycle_len); + } /* if (k == i) */ + cycle_len = 0; + } + + // Release allocated memory + free(cycle); +} + +/* +// Decision of two dimensional problem generalized distance transform +// on the regular grid at all points +// min{d2(y' - y) + d4(y' - y)(y' - y) + + min(d1(x' - x) + d3(x' - x)(x' - x) + f(x',y'))} (on x', y') +// +// API +// int DistanceTransformTwoDimensionalProblem(const float *f, + const int n, const int m, + const float coeff[4], + float *distanceTransform, + int *pointsX, int *pointsY); +// INPUT +// f - function on the regular grid +// n - number of rows +// m - number of columns +// coeff - coefficients of optimizable function + coeff[0] = d1, coeff[1] = d2, + coeff[2] = d3, coeff[3] = d4 +// OUTPUT +// distanceTransform - values of generalized distance transform +// pointsX - arguments x' that correspond to the optimal value +// pointsY - arguments y' that correspond to the optimal value +// RESULT +// Error status +*/ +int DistanceTransformTwoDimensionalProblem(const float *f, + const int n, const int m, + const float coeff[4], + float *distanceTransform, + int *pointsX, int *pointsY) +{ + int i, j, tmp; + int resOneDimProblem; + float *internalDistTrans; + int *internalPointsX; + int size = n * m; + + // Allocation memory (must be free in this function) + internalDistTrans = (float *)malloc(sizeof(float) * size); + internalPointsX = (int *)malloc(sizeof(int) * size); + + + for (i = 0; i < n; i++) + { + resOneDimProblem = DistanceTransformOneDimensionalProblem( + f + i * m, m, + coeff[0], coeff[2], + internalDistTrans + i * m, + internalPointsX + i * m); + if (resOneDimProblem != DISTANCE_TRANSFORM_OK) + { + free(internalDistTrans); + return DISTANCE_TRANSFORM_ERROR; + } /* if (resOneDimProblem != DISTANCE_TRANSFORM_OK) */ + } + Transpose(internalDistTrans, n, m); + for (j = 0; j < m; j++) + { + resOneDimProblem = DistanceTransformOneDimensionalProblem( + internalDistTrans + j * n, n, + coeff[1], coeff[3], + distanceTransform + j * n, + pointsY + j * n); + if (resOneDimProblem != DISTANCE_TRANSFORM_OK) + { + free(internalDistTrans); + return DISTANCE_TRANSFORM_ERROR; + } /* if (resOneDimProblem != DISTANCE_TRANSFORM_OK) */ + } + Transpose(distanceTransform, m, n); + Transpose_int(pointsY, m, n); + + for (i = 0; i < n; i++) + { + for (j = 0; j < m; j++) + { + tmp = pointsY[i * m + j]; + pointsX[i * m + j] = internalPointsX[tmp * m + j]; + } + } + + // Release allocated memory + free(internalDistTrans); + free(internalPointsX); + return DISTANCE_TRANSFORM_OK; +} \ No newline at end of file diff --git a/modules/objdetect/src/featurepyramid.cpp b/modules/objdetect/src/featurepyramid.cpp new file mode 100644 index 0000000000..217944701e --- /dev/null +++ b/modules/objdetect/src/featurepyramid.cpp @@ -0,0 +1,576 @@ +#include "_latentsvm.h" +#include "_resizeimg.h" + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int sign(float r){ + if(r > 0.0001f) return 1; + if(r < -0.0001f) return -1; + return 0; +} + +/* +// Getting feature map for the selected subimage +// +// API +// int getFeatureMaps(const IplImage * image, const int k, featureMap **map); +// INPUT +// image - selected subimage +// k - size of cells +// OUTPUT +// map - feature map +// RESULT +// Error status +*/ +int getFeatureMaps_dp(const IplImage * image,const int k, featureMap **map) +{ + int sizeX, sizeY; + int p, px, strsz; + int height, width, channels; + int i, j, kk, c, ii, jj, d; + float * datadx, * datady; + float tmp, x, y, tx, ty; + IplImage * dx, * dy; + int *nearest_x, *nearest_y; + float *w, a_x, b_x; + + float kernel[3] = {-1.f, 0.f, 1.f}; + CvMat kernel_dx = cvMat(1, 3, CV_32F, kernel); + CvMat kernel_dy = cvMat(3, 1, CV_32F, kernel); + + float * r; + int * alfa; + + float boundary_x[CNTPARTION+1]; + float boundary_y[CNTPARTION+1]; + float max, tmp_scal; + int maxi; + + height = image->height; + width = image->width ; + + channels = image->nChannels; + + dx = cvCreateImage(cvSize(image->width , image->height) , IPL_DEPTH_32F , 3); + dy = cvCreateImage(cvSize(image->width , image->height) , IPL_DEPTH_32F , 3); + + sizeX = width / k; + sizeY = height / k; + px = CNTPARTION + 2 * CNTPARTION; // контрастное и не контрастное изображение + p = px; + strsz = sizeX * p; + allocFeatureMapObject(map, sizeX, sizeY, p, px); + + cvFilter2D(image, dx, &kernel_dx, cvPoint(-1, 0)); + cvFilter2D(image, dy, &kernel_dy, cvPoint(0, -1)); + + for(i = 0; i <= CNTPARTION; i++) + { + boundary_x[i] = cosf((((float)i) * (((float)PI) / (float) (CNTPARTION)))); + boundary_y[i] = sinf((((float)i) * (((float)PI) / (float) (CNTPARTION)))); + }/*for(i = 0; i <= CNTPARTION; i++) */ + + r = (float *)malloc( sizeof(float) * (width * height)); + alfa = (int *)malloc( sizeof(int ) * (width * height * 2)); + + for(j = 1; j < height-1; j++) + { + datadx = (float*)(dx->imageData + dx->widthStep *j); + datady = (float*)(dy->imageData + dy->widthStep *j); + for(i = 1; i < width-1; i++) + { + c = 0; + x = (datadx[i*channels+c]); + y = (datady[i*channels+c]); + + r[j * width + i] =sqrtf(x*x + y*y); + for(kk = 1; kk < channels; kk++) + { + tx = (datadx[i*channels+kk]); + ty = (datady[i*channels+kk]); + tmp =sqrtf(tx*tx + ty*ty); + if(tmp > r[j * width + i]) + { + r[j * width + i] = tmp; + c = kk; + x = tx; + y = ty; + } + }/*for(kk = 1; kk < channels; kk++)*/ + + + + max = boundary_x[0]*x + boundary_y[0]*y; + maxi = 0; + for (kk = 0; kk < CNTPARTION; kk++) { + tmp_scal = boundary_x[kk]*x + boundary_y[kk]*y; + if (tmp_scal> max) { + max = tmp_scal; + maxi = kk; + }else if (-tmp_scal> max) { + max = -tmp_scal; + maxi = kk + CNTPARTION; + } + } + alfa[j * width * 2 + i * 2 ] = maxi % CNTPARTION; + alfa[j * width * 2 + i * 2 + 1] = maxi; + }/*for(i = 0; i < width; i++)*/ + }/*for(j = 0; j < height; j++)*/ + + //подсчет весов и смещений + nearest_x = (int *)malloc(sizeof(int) * k); + nearest_y = (int *)malloc(sizeof(int) * k); + w = (float*)malloc(sizeof(float) * (k * 2)); + + for(i = 0; i < k / 2; i++) + { + nearest_x[i] = -1; + nearest_y[i] = -1; + }/*for(i = 0; i < k / 2; i++)*/ + for(i = k / 2; i < k; i++) + { + nearest_x[i] = 1; + nearest_y[i] = 1; + }/*for(i = k / 2; i < k; i++)*/ + + for(j = 0; j < k / 2; j++) + { + b_x = k / 2 + j + 0.5f; + a_x = k / 2 - j - 0.5f; + w[j * 2 ] = 1.0f/a_x * ((a_x * b_x) / ( a_x + b_x)); + w[j * 2 + 1] = 1.0f/b_x * ((a_x * b_x) / ( a_x + b_x)); + }/*for(j = 0; j < k / 2; j++)*/ + for(j = k / 2; j < k; j++) + { + a_x = j - k / 2 + 0.5f; + b_x =-j + k / 2 - 0.5f + k; + w[j * 2 ] = 1.0f/a_x * ((a_x * b_x) / ( a_x + b_x)); + w[j * 2 + 1] = 1.0f/b_x * ((a_x * b_x) / ( a_x + b_x)); + }/*for(j = k / 2; j < k; j++)*/ + + + //интерполяция + for(i = 0; i < sizeY; i++) + { + for(j = 0; j < sizeX; j++) + { + for(ii = 0; ii < k; ii++) + { + for(jj = 0; jj < k; jj++) + { + if ((i * k + ii > 0) && (i * k + ii < height - 1) && (j * k + jj > 0) && (j * k + jj < width - 1)) + { + d = (k*i + ii)* width + (j*k + jj); + (*map)->Map[(i ) * strsz + (j ) * (*map)->p + alfa[d * 2 ] ] += + r[d] * w[ii * 2 ] * w[jj * 2 ]; + (*map)->Map[(i ) * strsz + (j ) * (*map)->p + alfa[d * 2 + 1] + CNTPARTION] += + r[d] * w[ii * 2 ] * w[jj * 2 ]; + if ((i + nearest_y[ii] >= 0) && (i + nearest_y[ii] <= sizeY - 1)) + { + (*map)->Map[(i + nearest_y[ii]) * strsz + (j ) * (*map)->p + alfa[d * 2 ] ] += + r[d] * w[ii * 2 + 1] * w[jj * 2 ]; + (*map)->Map[(i + nearest_y[ii]) * strsz + (j ) * (*map)->p + alfa[d * 2 + 1] + CNTPARTION] += + r[d] * w[ii * 2 + 1] * w[jj * 2 ]; + } + if ((j + nearest_x[jj] >= 0) && (j + nearest_x[jj] <= sizeX - 1)) + { + (*map)->Map[(i ) * strsz + (j + nearest_x[jj]) * (*map)->p + alfa[d * 2 ] ] += + r[d] * w[ii * 2 ] * w[jj * 2 + 1]; + (*map)->Map[(i ) * strsz + (j + nearest_x[jj]) * (*map)->p + alfa[d * 2 + 1] + CNTPARTION] += + r[d] * w[ii * 2 ] * w[jj * 2 + 1]; + } + if ((i + nearest_y[ii] >= 0) && (i + nearest_y[ii] <= sizeY - 1) && (j + nearest_x[jj] >= 0) && (j + nearest_x[jj] <= sizeX - 1)) + { + (*map)->Map[(i + nearest_y[ii]) * strsz + (j + nearest_x[jj]) * (*map)->p + alfa[d * 2 ] ] += + r[d] * w[ii * 2 + 1] * w[jj * 2 + 1]; + (*map)->Map[(i + nearest_y[ii]) * strsz + (j + nearest_x[jj]) * (*map)->p + alfa[d * 2 + 1] + CNTPARTION] += + r[d] * w[ii * 2 + 1] * w[jj * 2 + 1]; + } + } + }/*for(jj = 0; jj < k; jj++)*/ + }/*for(ii = 0; ii < k; ii++)*/ + }/*for(j = 1; j < sizeX - 1; j++)*/ + }/*for(i = 1; i < sizeY - 1; i++)*/ + + cvReleaseImage(&dx); + cvReleaseImage(&dy); + + + free(w); + free(nearest_x); + free(nearest_y); + + free(r); + free(alfa); + + return LATENT_SVM_OK; +} + +/* +// Feature map Normalization and Truncation +// +// API +// int normalizationAndTruncationFeatureMaps(featureMap *map, const float alfa); +// INPUT +// map - feature map +// alfa - truncation threshold +// OUTPUT +// map - truncated and normalized feature map +// RESULT +// Error status +*/ +int normalizationAndTruncationFeatureMaps(featureMap *map, const float alfa) +{ + int i,j, ii; + int sizeX, sizeY, p, pos, pp, xp, pos1, pos2; + float * part_noma; // norm of C(i, j) + float * new_data; + float norm_val; + + sizeX = map->sizeX; + sizeY = map->sizeY; + part_noma = (float *)malloc (sizeof(float) * (sizeX * sizeY)); + + p = map->xp / 3; + + for(i = 0; i < sizeX * sizeY; i++) + { + norm_val = 0.0; + pos = i * map->p; + for(j = 0; j < p; j++) + { + norm_val += map->Map[pos + j] * map->Map[pos + j]; + }/*for(j = 0; j < p; j++)*/ + part_noma[i] = norm_val; + }/*for(i = 0; i < sizeX * sizeY; i++)*/ + + xp = map->xp; + pp = xp * 4; + sizeX -= 2; + sizeY -= 2; + + new_data = (float *)malloc (sizeof(float) * (sizeX * sizeY * pp)); +//normalization + for(i = 1; i <= sizeY; i++) + { + for(j = 1; j <= sizeX; j++) + { + norm_val = sqrtf( + part_noma[(i )*(sizeX + 2) + (j )] + + part_noma[(i )*(sizeX + 2) + (j + 1)] + + part_noma[(i + 1)*(sizeX + 2) + (j )] + + part_noma[(i + 1)*(sizeX + 2) + (j + 1)]); + pos1 = (i ) * (sizeX + 2) * xp + (j ) * xp; + pos2 = (i-1) * (sizeX ) * pp + (j-1) * pp; + for(ii = 0; ii < p; ii++) + { + new_data[pos2 + ii ] = map->Map[pos1 + ii ] / norm_val; + }/*for(ii = 0; ii < p; ii++)*/ + for(ii = 0; ii < 2 * p; ii++) + { + new_data[pos2 + ii + p * 4] = map->Map[pos1 + ii + p] / norm_val; + }/*for(ii = 0; ii < 2 * p; ii++)*/ + norm_val = sqrtf( + part_noma[(i )*(sizeX + 2) + (j )] + + part_noma[(i )*(sizeX + 2) + (j + 1)] + + part_noma[(i - 1)*(sizeX + 2) + (j )] + + part_noma[(i - 1)*(sizeX + 2) + (j + 1)]); + for(ii = 0; ii < p; ii++) + { + new_data[pos2 + ii + p ] = map->Map[pos1 + ii ] / norm_val; + }/*for(ii = 0; ii < p; ii++)*/ + for(ii = 0; ii < 2 * p; ii++) + { + new_data[pos2 + ii + p * 6] = map->Map[pos1 + ii + p] / norm_val; + }/*for(ii = 0; ii < 2 * p; ii++)*/ + norm_val = sqrtf( + part_noma[(i )*(sizeX + 2) + (j )] + + part_noma[(i )*(sizeX + 2) + (j - 1)] + + part_noma[(i + 1)*(sizeX + 2) + (j )] + + part_noma[(i + 1)*(sizeX + 2) + (j - 1)]); + for(ii = 0; ii < p; ii++) + { + new_data[pos2 + ii + p * 2] = map->Map[pos1 + ii ] / norm_val; + }/*for(ii = 0; ii < p; ii++)*/ + for(ii = 0; ii < 2 * p; ii++) + { + new_data[pos2 + ii + p * 8] = map->Map[pos1 + ii + p] / norm_val; + }/*for(ii = 0; ii < 2 * p; ii++)*/ + norm_val = sqrtf( + part_noma[(i )*(sizeX + 2) + (j )] + + part_noma[(i )*(sizeX + 2) + (j - 1)] + + part_noma[(i - 1)*(sizeX + 2) + (j )] + + part_noma[(i - 1)*(sizeX + 2) + (j - 1)]); + for(ii = 0; ii < p; ii++) + { + new_data[pos2 + ii + p * 3 ] = map->Map[pos1 + ii ] / norm_val; + }/*for(ii = 0; ii < p; ii++)*/ + for(ii = 0; ii < 2 * p; ii++) + { + new_data[pos2 + ii + p * 10] = map->Map[pos1 + ii + p] / norm_val; + }/*for(ii = 0; ii < 2 * p; ii++)*/ + }/*for(j = 1; j <= sizeX; j++)*/ + }/*for(i = 1; i <= sizeY; i++)*/ +//truncation + for(i = 0; i < sizeX * sizeY * pp; i++) + { + if(new_data [i] > alfa) new_data [i] = alfa; + }/*for(i = 0; i < sizeX * sizeY * pp; i++)*/ +//swop data + + map->p = pp; + map->xp = xp; + map->sizeX = sizeX; + map->sizeY = sizeY; + + free (map->Map); + free (part_noma); + + map->Map = new_data; + + return LATENT_SVM_OK; +} +/* +// Feature map reduction +// In each cell we reduce dimension of the feature vector +// according to original paper special procedure +// +// API +// int PCAFeatureMaps(featureMap *map) +// INPUT +// map - feature map +// OUTPUT +// map - feature map +// RESULT +// Error status +*/ +int PCAFeatureMaps(featureMap *map) +{ + int i,j, ii, jj, k; + int sizeX, sizeY, p, pp, xp, yp, pos1, pos2; + float * new_data; + float val; + float nx, ny; + + sizeX = map->sizeX; + sizeY = map->sizeY; + p = map->p; + pp = map->xp + 4; + yp = 4; + xp = (map->xp / 3); + + nx = 1.0f / sqrtf((float)(xp * 2)); + ny = 1.0f / sqrtf((float)(yp )); + + new_data = (float *)malloc (sizeof(float) * (sizeX * sizeY * pp)); + + for(i = 0; i < sizeY; i++) + { + for(j = 0; j < sizeX; j++) + { + pos1 = ((i)*sizeX + j)*p; + pos2 = ((i)*sizeX + j)*pp; + k = 0; + for(jj = 0; jj < xp * 2; jj++) + { + val = 0; + for(ii = 0; ii < yp; ii++) + { + val += map->Map[pos1 + yp * xp + ii * xp * 2 + jj]; + }/*for(ii = 0; ii < yp; ii++)*/ + new_data[pos2 + k] = val * ny; + k++; + }/*for(jj = 0; jj < xp * 2; jj++)*/ + for(jj = 0; jj < xp; jj++) + { + val = 0; + for(ii = 0; ii < yp; ii++) + { + val += map->Map[pos1 + ii * xp + jj]; + }/*for(ii = 0; ii < yp; ii++)*/ + new_data[pos2 + k] = val * ny; + k++; + }/*for(jj = 0; jj < xp; jj++)*/ + for(ii = 0; ii < yp; ii++) + { + val = 0; + for(jj = 0; jj < 2 * xp; jj++) + { + val += map->Map[pos1 + yp * xp + ii * xp * 2 + jj]; + }/*for(jj = 0; jj < xp; jj++)*/ + new_data[pos2 + k] = val * nx; + k++; + } /*for(ii = 0; ii < yp; ii++)*/ + }/*for(j = 0; j < sizeX; j++)*/ + }/*for(i = 0; i < sizeY; i++)*/ +//swop data + + map->p = pp; + map->xp = pp; + + free (map->Map); + + map->Map = new_data; + + return LATENT_SVM_OK; +} + +/* +// Getting feature pyramid +// +// API +// int getFeaturePyramid(IplImage * image, const filterObject **all_F, + const int n_f, + const int lambda, const int k, + const int startX, const int startY, + const int W, const int H, featurePyramid **maps); +// INPUT +// image - image +// lambda - resize scale +// k - size of cells +// startX - X coordinate of the image rectangle to search +// startY - Y coordinate of the image rectangle to search +// W - width of the image rectangle to search +// H - height of the image rectangle to search +// OUTPUT +// maps - feature maps for all levels +// RESULT +// Error status +*/ +int getFeaturePyramid(IplImage * image, + const int lambda, const int k, + const int startX, const int startY, + const int W, const int H, featurePyramid **maps) +{ + IplImage *img2, *imgTmp, *imgResize; + float step, tmp; + int cntStep; + int maxcall; + int i; + int err; + featureMap *map; + + //geting subimage + cvSetImageROI(image, cvRect(startX, startY, W, H)); + img2 = cvCreateImage(cvGetSize(image), image->depth, image->nChannels); + cvCopy(image, img2, NULL); + cvResetImageROI(image); + + if(img2->depth != IPL_DEPTH_32F) + { + imgResize = cvCreateImage(cvSize(img2->width , img2->height) , IPL_DEPTH_32F , 3); + cvConvert(img2, imgResize); + } + else + { + imgResize = img2; + } + + step = powf(2.0f, 1.0f/ ((float)lambda)); + maxcall = W/k; + if( maxcall > H/k ) + { + maxcall = H/k; + } + cntStep = (int)(logf((float)maxcall/(5.0f))/logf(step)) + 1; + //printf("Count step: %f %d\n", step, cntStep); + + allocFeaturePyramidObject(maps, lambda, cntStep + lambda); + + for(i = 0; i < lambda; i++) + { + tmp = 1.0f / powf(step, (float)i); + imgTmp = resize_opencv (imgResize, tmp); + //imgTmp = resize_article_dp(img2, tmp, 4); + err = getFeatureMaps_dp(imgTmp, 4, &map); + err = normalizationAndTruncationFeatureMaps(map, 0.2f); + err = PCAFeatureMaps(map); + (*maps)->pyramid[i] = map; + //printf("%d, %d\n", map->sizeY, map->sizeX); + cvReleaseImage(&imgTmp); + } + + /**********************************one**************/ + for(i = 0; i < cntStep; i++) + { + tmp = 1.0f / powf(step, (float)i); + imgTmp = resize_opencv (imgResize, tmp); + //imgTmp = resize_article_dp(imgResize, tmp, 8); + err = getFeatureMaps_dp(imgTmp, 8, &map); + err = normalizationAndTruncationFeatureMaps(map, 0.2f); + err = PCAFeatureMaps(map); + (*maps)->pyramid[i + lambda] = map; + //printf("%d, %d\n", map->sizeY, map->sizeX); + cvReleaseImage(&imgTmp); + }/*for(i = 0; i < cntStep; i++)*/ + + if(img2->depth != IPL_DEPTH_32F) + { + cvReleaseImage(&imgResize); + } + + cvReleaseImage(&img2); + return LATENT_SVM_OK; +} + +/* +// add zero border to feature map +// +// API +// int addBordersToFeatureMaps(featureMap *map, const int bX, const int bY); +// INPUT +// map - feature map +// bX - border size in x +// bY - border size in y +// OUTPUT +// map - feature map +// RESULT +// Error status +*/ +int addBordersToFeatureMaps(featureMap *map, const int bX, const int bY){ + int i,j, jj; + int sizeX, sizeY, p, pos1, pos2; + float * new_data; + + sizeX = map->sizeX; + sizeY = map->sizeY; + p = map->p; + + new_data = (float *)malloc (sizeof(float) * ((sizeX + 2 * bX) * (sizeY + 2 * bY) * p)); + + for(i = 0; i < ((sizeX + 2 * bX) * (sizeY + 2 * bY) * p); i++) + { + new_data[i] = (float)0; + }/*for(i = 0; i < ((sizeX + 2 * bX) * (sizeY + 2 * bY) * p); i++)*/ + + for(i = 0; i < sizeY; i++) + { + for(j = 0; j < sizeX; j++) + { + + pos1 = ((i )*sizeX + (j )) * p; + pos2 = ((i + bY)*(sizeX + 2 * bX) + (j + bX)) * p; + + for(jj = 0; jj < p; jj++) + { + new_data[pos2 + jj] = map->Map[pos1 + jj]; + }/*for(jj = 0; jj < p; jj++)*/ + }/*for(j = 0; j < sizeX; j++)*/ + }/*for(i = 0; i < sizeY; i++)*/ + //swop data + + map->sizeX = sizeX + 2 * bX; + map->sizeY = sizeY + 2 * bY; + + free (map->Map); + + map->Map = new_data; + + return LATENT_SVM_OK; +} \ No newline at end of file diff --git a/modules/objdetect/src/fft.cpp b/modules/objdetect/src/fft.cpp new file mode 100644 index 0000000000..e4d974a8c9 --- /dev/null +++ b/modules/objdetect/src/fft.cpp @@ -0,0 +1,246 @@ +#include "_fft.h" + +int getEntireRes(int number, int divisor, int *entire, int *res) +{ + *entire = number / divisor; + *res = number % divisor; + return FFT_OK; +} + +int getMultipliers(int n, int *n1, int *n2) +{ + int multiplier, i; + if (n == 1) + { + *n1 = 1; + *n2 = 1; + return FFT_ERROR; // n = 1 + } + multiplier = n / 2; + for (i = multiplier; i >= 2; i--) + { + if (n % i == 0) + { + *n1 = i; + *n2 = n / i; + return FFT_OK; // n = n1 * n2 + } + } + *n1 = 1; + *n2 = n; + return FFT_ERROR; // n - prime number +} + +/* +// 1-dimensional FFT +// +// API +// int fft(float *x_in, float *x_out, int n, int shift); +// INPUT +// x_in - input signal +// n - number of elements for searching Fourier image +// shift - shift between input elements +// OUTPUT +// x_out - output signal (contains 2n elements in order + Re(x_in[0]), Im(x_in[0]), Re(x_in[1]), Im(x_in[1]) and etc.) +// RESULT +// Error status +*/ +int fft(float *x_in, float *x_out, int n, int shift) +{ + int n1, n2, res, k1, k2, m1, m2, index, idx; + float alpha, beta, gamma, angle, cosAngle, sinAngle; + float tmpGamma, tmpAlpha, tmpBeta; + float tmpRe, tmpIm, phaseRe, phaseIm; + res = getMultipliers(n, &n1, &n2); + if (res == FFT_OK) + { + fft(x_in, x_out, n1, shift); + fft(x_in, x_out, n2, shift); + } + alpha = (float)(2.0 * PI / ((float)n)); + beta = (float)(2.0 * PI / ((float)n1)); + gamma = (float)(2.0 * PI / ((float)n2)); + for (k1 = 0; k1 < n1; k1++) + { + tmpBeta = beta * k1; + for (k2 = 0; k2 < n2; k2++) + { + idx = shift * (n2 * k1 + k2); + x_out[idx] = 0.0; + x_out[idx + 1] = 0.0; + tmpGamma = gamma * k2; + tmpAlpha = alpha * k2; + for (m1 = 0; m1 < n1; m1++) + { + tmpRe = 0.0; + tmpIm = 0.0; + for (m2 = 0; m2 < n2; m2++) + { + angle = tmpGamma * m2; + index = shift * (n1 * m2 + m1); + cosAngle = cosf(angle); + sinAngle = sinf(angle); + tmpRe += x_in[index] * cosAngle + x_in[index + 1] * sinAngle; + tmpIm += x_in[index + 1] * cosAngle - x_in[index] * sinAngle; + } + angle = tmpAlpha * m1; + cosAngle = cosf(angle); + sinAngle = sinf(angle); + phaseRe = cosAngle * tmpRe + sinAngle * tmpIm; + phaseIm = cosAngle * tmpIm - sinAngle * tmpRe; + angle = tmpBeta * m1; + cosAngle = cosf(angle); + sinAngle = sinf(angle); + x_out[idx] += (cosAngle * phaseRe + sinAngle * phaseIm); + x_out[idx + 1] += (cosAngle * phaseIm - sinAngle * phaseRe); + } + } + } + return FFT_OK; +} + +/* +// Inverse 1-dimensional FFT +// +// API +// int fftInverse(float *x_in, float *x_out, int n, int shift); +// INPUT +// x_in - Fourier image of 1d input signal(contains 2n elements + in order Re(x_in[0]), Im(x_in[0]), + Re(x_in[1]), Im(x_in[1]) and etc.) +// n - number of elements for searching counter FFT image +// shift - shift between input elements +// OUTPUT +// x_in - input signal (contains n elements) +// RESULT +// Error status +*/ +int fftInverse(float *x_in, float *x_out, int n, int shift) +{ + int n1, n2, res, k1, k2, m1, m2, index, idx; + float alpha, beta, gamma, angle, cosAngle, sinAngle; + float tmpRe, tmpIm, phaseRe, phaseIm; + res = getMultipliers(n, &n1, &n2); + if (res == FFT_OK) + { + fftInverse(x_in, x_out, n1, shift); + fftInverse(x_in, x_out, n2, shift); + } + alpha = (float)(2.0f * PI / ((float)n)); + beta = (float)(2.0f * PI / ((float)n1)); + gamma = (float)(2.0f * PI / ((float)n2)); + for (m1 = 0; m1 < n1; m1++) + { + for (m2 = 0; m2 < n2; m2++) + { + idx = (n1 * m2 + m1) * shift; + x_out[idx] = 0.0; + x_out[idx + 1] = 0.0; + for (k2 = 0; k2 < n2; k2++) + { + tmpRe = 0.0; + tmpIm = 0.0; + for (k1 = 0; k1 < n1; k1++) + { + angle = beta * k1 * m1; + index = shift *(n2 * k1 + k2); + sinAngle = sinf(angle); + cosAngle = cosf(angle); + tmpRe += x_in[index] * cosAngle - x_in[index + 1] * sinAngle; + tmpIm += x_in[index] * sinAngle + x_in[index + 1] * cosAngle; + } + angle = alpha * m1 * k2; + sinAngle = sinf(angle); + cosAngle = cosf(angle); + phaseRe = cosAngle * tmpRe - sinAngle * tmpIm; + phaseIm = cosAngle * tmpIm + sinAngle * tmpRe; + angle = gamma * k2 * m2; + sinAngle = sinf(angle); + cosAngle = cosf(angle); + x_out[idx] += cosAngle * phaseRe - sinAngle * phaseIm; + x_out[idx + 1] += cosAngle * phaseIm + sinAngle * phaseRe; + } + x_out[idx] /= n; + x_out[idx + 1] /= n; + } + } + return FFT_OK; +} + +/* +// 2-dimensional FFT +// +// API +// int fft2d(float *x_in, float *x_out, int numRows, int numColls); +// INPUT +// x_in - input signal (matrix, launched by rows) +// numRows - number of rows +// numColls - number of collumns +// OUTPUT +// x_out - output signal (contains (2 * numRows * numColls) elements + in order Re(x_in[0][0]), Im(x_in[0][0]), + Re(x_in[0][1]), Im(x_in[0][1]) and etc.) +// RESULT +// Error status +*/ +int fft2d(float *x_in, float *x_out, int numRows, int numColls) +{ + int i, size; + float *x_outTmp; + size = numRows * numColls; + x_outTmp = (float *)malloc(sizeof(float) * (2 * size)); + for (i = 0; i < numRows; i++) + { + fft(x_in + i * 2 * numColls, + x_outTmp + i * 2 * numColls, + numColls, 2); + } + for (i = 0; i < numColls; i++) + { + fft(x_outTmp + 2 * i, + x_out + 2 * i, + numRows, 2 * numColls); + } + free(x_outTmp); + return FFT_OK; +} + +/* +// Inverse 2-dimensional FFT +// +// API +// int fftInverse2d(float *x_in, float *x_out, int numRows, int numColls); +// INPUT +// x_in - Fourier image of matrix (contains (2 * numRows * numColls) + elements in order Re(x_in[0][0]), Im(x_in[0][0]), + Re(x_in[0][1]), Im(x_in[0][1]) and etc.) +// numRows - number of rows +// numColls - number of collumns +// OUTPUT +// x_out - initial signal (matrix, launched by rows) +// RESULT +// Error status +*/ +int fftInverse2d(float *x_in, float *x_out, int numRows, int numColls) +{ + int i, size; + float *x_outTmp; + size = numRows * numColls; + x_outTmp = (float *)malloc(sizeof(float) * (2 * size)); + for (i = 0; i < numRows; i++) + { + fftInverse(x_in + i * 2 * numColls, + x_outTmp + i * 2 * numColls, + numColls, 2); + } + for (i = 0; i < numColls; i++) + { + fftInverse(x_outTmp + 2 * i, + x_out + 2 * i, + numRows, 2 * numColls); + } + free(x_outTmp); + return FFT_OK; +} + diff --git a/modules/objdetect/src/latentsvm.cpp b/modules/objdetect/src/latentsvm.cpp new file mode 100644 index 0000000000..2a811f97ca --- /dev/null +++ b/modules/objdetect/src/latentsvm.cpp @@ -0,0 +1,611 @@ +#include "_latentsvm.h" +#include "_matching.h" + +/* +// Transformation filter displacement from the block space +// to the space of pixels at the initial image +// +// API +// int convertPoints(int countLevel, CvPoint *points, int *levels, + CvPoint **partsDisplacement, int kPoints, int n); +// INPUT +// countLevel - the number of levels in the feature pyramid +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// partsDisplacement - displacement of part filters (in the block space) +// kPoints - number of root filter positions +// n - number of part filters +// initialImageLevel - level that contains features for initial image +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// points - the set of root filter positions (in the space of pixels) +// partsDisplacement - displacement of part filters (in the space of pixels) +// RESULT +// Error status +*/ +int convertPoints(int countLevel, int lambda, + int initialImageLevel, + CvPoint *points, int *levels, + CvPoint **partsDisplacement, int kPoints, int n, + int maxXBorder, + int maxYBorder) +{ + int i, j, bx, by; + float step, scale; + step = powf( 2.0f, 1.0f / ((float)lambda) ); + + computeBorderSize(maxXBorder, maxYBorder, &bx, &by); + + for (i = 0; i < kPoints; i++) + { + // scaling factor for root filter + scale = SIDE_LENGTH * powf(step, (float)(levels[i] - initialImageLevel)); + points[i].x = (int)((points[i].x - bx + 1) * scale); + points[i].y = (int)((points[i].y - by + 1) * scale); + + // scaling factor for part filters + scale = SIDE_LENGTH * powf(step, (float)(levels[i] - lambda - initialImageLevel)); + for (j = 0; j < n; j++) + { + partsDisplacement[i][j].x = (int)((partsDisplacement[i][j].x - + 2 * bx + 1) * scale); + partsDisplacement[i][j].y = (int)((partsDisplacement[i][j].y - + 2 * by + 1) * scale); + } + } + return LATENT_SVM_OK; +} + +/* +// Elimination boxes that are outside the image boudaries +// +// API +// int clippingBoxes(int width, int height, + CvPoint *points, int kPoints); +// INPUT +// width - image wediht +// height - image heigth +// points - a set of points (coordinates of top left or + bottom right corners) +// kPoints - points number +// OUTPUT +// points - updated points (if coordinates less than zero then + set zero coordinate, if coordinates more than image + size then set coordinates equal image size) +// RESULT +// Error status +*/ +int clippingBoxes(int width, int height, + CvPoint *points, int kPoints) +{ + int i; + for (i = 0; i < kPoints; i++) + { + if (points[i].x > width - 1) + { + points[i].x = width - 1; + } + if (points[i].x < 0) + { + points[i].x = 0; + } + if (points[i].y > height - 1) + { + points[i].y = height - 1; + } + if (points[i].y < 0) + { + points[i].y = 0; + } + } + return LATENT_SVM_OK; +} + +/* +// Creation feature pyramid with nullable border +// +// API +// featurePyramid* createFeaturePyramidWithBorder(const IplImage *image, + int maxXBorder, int maxYBorder); + +// INPUT +// image - initial image +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// RESULT +// Feature pyramid with nullable border +*/ +featurePyramid* createFeaturePyramidWithBorder(IplImage *image, + int maxXBorder, int maxYBorder) +{ + int opResult; + int bx, by; + int level; + featurePyramid *H; + + // Obtaining feature pyramid + opResult = getFeaturePyramid(image, LAMBDA, SIDE_LENGTH, 0, 0, + image->width, image->height, &H); + + if (opResult != LATENT_SVM_OK) + { + freeFeaturePyramidObject(&H); + return NULL; + } /* if (opResult != LATENT_SVM_OK) */ + + // Addition nullable border for each feature map + // the size of the border for root filters + computeBorderSize(maxXBorder, maxYBorder, &bx, &by); + for (level = 0; level < H->countLevel; level++) + { + addNullableBorder(H->pyramid[level], bx, by); + } + return H; +} + +/* +// Computation of the root filter displacement and values of score function +// +// API +// int searchObject(const featurePyramid *H, const filterObject **all_F, int n, + float b, + int maxXBorder, + int maxYBorder, + CvPoint **points, int **levels, int *kPoints, float *score, + CvPoint ***partsDisplacement); +// INPUT +// image - initial image for searhing object +// all_F - the set of filters (the first element is root filter, + other elements - part filters) +// n - the number of part filters +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// points - positions (x, y) of the upper-left corner + of root filter frame +// levels - levels that correspond to each position +// kPoints - number of positions +// score - value of the score function +// partsDisplacement - part filters displacement for each position + of the root filter +// RESULT +// Error status +*/ +int searchObject(const featurePyramid *H, const filterObject **all_F, + int n, float b, + int maxXBorder, + int maxYBorder, + CvPoint **points, int **levels, int *kPoints, float *score, + CvPoint ***partsDisplacement) +{ + int opResult; + + // Matching + opResult = maxFunctionalScore(all_F, n, H, b, maxXBorder, maxYBorder, + score, points, levels, + kPoints, partsDisplacement); + if (opResult != LATENT_SVM_OK) + { + return LATENT_SVM_SEARCH_OBJECT_FAILED; + } + + // Transformation filter displacement from the block space + // to the space of pixels at the initial image + // that settles at the level number LAMBDA + convertPoints(H->countLevel, H->lambda, LAMBDA, (*points), + (*levels), (*partsDisplacement), (*kPoints), n, + maxXBorder, maxYBorder); + + return LATENT_SVM_OK; +} + +/* +// Computation right bottom corners coordinates of bounding boxes +// +// API +// int estimateBoxes(CvPoint *points, int *levels, int kPoints, + int sizeX, int sizeY, CvPoint **oppositePoints); +// INPUT +// points - left top corners coordinates of bounding boxes +// levels - levels of feature pyramid where points were found +// (sizeX, sizeY) - size of root filter +// OUTPUT +// oppositePoins - right bottom corners coordinates of bounding boxes +// RESULT +// Error status +*/ +int estimateBoxes(CvPoint *points, int *levels, int kPoints, + int sizeX, int sizeY, CvPoint **oppositePoints) +{ + int i; + float step; + + step = powf( 2.0f, 1.0f / ((float)(LAMBDA))); + + *oppositePoints = (CvPoint *)malloc(sizeof(CvPoint) * kPoints); + for (i = 0; i < kPoints; i++) + { + getOppositePoint(points[i], sizeX, sizeY, step, levels[i] - LAMBDA, &((*oppositePoints)[i])); + } + return LATENT_SVM_OK; +} + +/* +// Computation of the root filter displacement and values of score function +// +// API +// int searchObjectThreshold(const featurePyramid *H, + const filterObject **all_F, int n, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + CvPoint **points, int **levels, int *kPoints, + float **score, CvPoint ***partsDisplacement); +// INPUT +// H - feature pyramid +// all_F - the set of filters (the first element is root filter, + other elements - part filters) +// n - the number of part filters +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// points - positions (x, y) of the upper-left corner + of root filter frame +// levels - levels that correspond to each position +// kPoints - number of positions +// score - values of the score function +// partsDisplacement - part filters displacement for each position + of the root filter +// RESULT +// Error status +*/ +int searchObjectThreshold(const featurePyramid *H, + const filterObject **all_F, int n, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + CvPoint **points, int **levels, int *kPoints, + float **score, CvPoint ***partsDisplacement) +{ + int opResult; + + + // Matching + opResult = thresholdFunctionalScore(all_F, n, H, b, + maxXBorder, maxYBorder, + scoreThreshold, + score, points, levels, + kPoints, partsDisplacement); + if (opResult != LATENT_SVM_OK) + { + return LATENT_SVM_SEARCH_OBJECT_FAILED; + } + + // Transformation filter displacement from the block space + // to the space of pixels at the initial image + // that settles at the level number LAMBDA + convertPoints(H->countLevel, H->lambda, LAMBDA, (*points), + (*levels), (*partsDisplacement), (*kPoints), n, + maxXBorder, maxYBorder); + + return LATENT_SVM_OK; +} + +/* +// Compute opposite point for filter box +// +// API +// int getOppositePoint(CvPoint point, + int sizeX, int sizeY, + float step, int degree, + CvPoint *oppositePoint); + +// INPUT +// point - coordinates of filter top left corner + (in the space of pixels) +// (sizeX, sizeY) - filter dimension in the block space +// step - scaling factor +// degree - degree of the scaling factor +// OUTPUT +// oppositePoint - coordinates of filter bottom corner + (in the space of pixels) +// RESULT +// Error status +*/ +int getOppositePoint(CvPoint point, + int sizeX, int sizeY, + float step, int degree, + CvPoint *oppositePoint) +{ + float scale; + scale = SIDE_LENGTH * powf(step, (float)degree); + oppositePoint->x = (int)(point.x + sizeX * scale); + oppositePoint->y = (int)(point.y + sizeY * scale); + return LATENT_SVM_OK; +} + + +/* +// Drawing root filter boxes +// +// API +// int showRootFilterBoxes(const IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); +// INPUT +// image - initial image +// filter - root filter object +// points - a set of points +// levels - levels of feature pyramid +// kPoints - number of points +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// window contained initial image and filter boxes +// RESULT +// Error status +*/ +int showRootFilterBoxes(IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift) +{ + int i; + float step; + CvPoint oppositePoint; + step = powf( 2.0f, 1.0f / ((float)LAMBDA)); + + for (i = 0; i < kPoints; i++) + { + // Drawing rectangle for filter + getOppositePoint(points[i], filter->sizeX, filter->sizeY, + step, levels[i] - LAMBDA, &oppositePoint); + cvRectangle(image, points[i], oppositePoint, + color, thickness, line_type, shift); + } + cvShowImage("Initial image", image); + return LATENT_SVM_OK; +} + +/* +// Drawing part filter boxes +// +// API +// int showPartFilterBoxes(const IplImage *image, + const filterObject *filter, + CvPoint *points, int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift); +// INPUT +// image - initial image +// filters - a set of part filters +// n - number of part filters +// partsDisplacement - a set of points +// levels - levels of feature pyramid +// kPoints - number of foot filter positions +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// window contained initial image and filter boxes +// RESULT +// Error status +*/ +int showPartFilterBoxes(IplImage *image, + const filterObject **filters, + int n, CvPoint **partsDisplacement, + int *levels, int kPoints, + CvScalar color, int thickness, + int line_type, int shift) +{ + int i, j; + float step; + CvPoint oppositePoint; + + step = powf( 2.0f, 1.0f / ((float)LAMBDA)); + + for (i = 0; i < kPoints; i++) + { + for (j = 0; j < n; j++) + { + // Drawing rectangles for part filters + getOppositePoint(partsDisplacement[i][j], + filters[j + 1]->sizeX, filters[j + 1]->sizeY, + step, levels[i] - 2 * LAMBDA, &oppositePoint); + cvRectangle(image, partsDisplacement[i][j], oppositePoint, + color, thickness, line_type, shift); + } + } + cvShowImage("Initial image", image); + return LATENT_SVM_OK; +} + +/* +// Drawing boxes +// +// API +// int showBoxes(const IplImage *img, + const CvPoint *points, const CvPoint *oppositePoints, int kPoints, + CvScalar color, int thickness, int line_type, int shift); +// INPUT +// img - initial image +// points - top left corner coordinates +// oppositePoints - right bottom corner coordinates +// kPoints - points number +// color - line color for each box +// thickness - line thickness +// line_type - line type +// shift - shift +// OUTPUT +// RESULT +// Error status +*/ +int showBoxes(IplImage *img, + const CvPoint *points, const CvPoint *oppositePoints, int kPoints, + CvScalar color, int thickness, int line_type, int shift) +{ + int i; + for (i = 0; i < kPoints; i++) + { + cvRectangle(img, points[i], oppositePoints[i], + color, thickness, line_type, shift); + } + cvShowImage("Initial image", img); + return LATENT_SVM_OK; +} + +/* +// Computation maximum filter size for each dimension +// +// API +// int getMaxFilterDims(const filterObject **filters, int kComponents, + const int *kPartFilters, + unsigned int *maxXBorder, unsigned int *maxYBorder); +// INPUT +// filters - a set of filters (at first root filter, then part filters + and etc. for all components) +// kComponents - number of components +// kPartFilters - number of part filters for each component +// OUTPUT +// maxXBorder - maximum of filter size at the horizontal dimension +// maxYBorder - maximum of filter size at the vertical dimension +// RESULT +// Error status +*/ +int getMaxFilterDims(const filterObject **filters, int kComponents, + const int *kPartFilters, + unsigned int *maxXBorder, unsigned int *maxYBorder) +{ + int i, componentIndex; + *maxXBorder = filters[0]->sizeX; + *maxYBorder = filters[0]->sizeY; + componentIndex = kPartFilters[0] + 1; + for (i = 1; i < kComponents; i++) + { + if (filters[componentIndex]->sizeX > *maxXBorder) + { + *maxXBorder = filters[componentIndex]->sizeX; + } + if (filters[componentIndex]->sizeY > *maxYBorder) + { + *maxYBorder = filters[componentIndex]->sizeY; + } + componentIndex += (kPartFilters[i] + 1); + } + return LATENT_SVM_OK; +} + +/* +// Computation root filters displacement and values of score function +// +// API +// int searchObjectThresholdSomeComponents(const featurePyramid *H, + const filterObject **filters, + int kComponents, const int *kPartFilters, + const float *b, float scoreThreshold, + CvPoint **points, CvPoint **oppPoints, + float **score, int *kPoints); +// INPUT +// H - feature pyramid +// filters - filters (root filter then it's part filters, etc.) +// kComponents - root filters number +// kPartFilters - array of part filters number for each component +// b - array of linear terms +// scoreThreshold - score threshold +// OUTPUT +// points - root filters displacement (top left corners) +// oppPoints - root filters displacement (bottom right corners) +// score - array of score values +// kPoints - number of boxes +// RESULT +// Error status +*/ +int searchObjectThresholdSomeComponents(const featurePyramid *H, + const filterObject **filters, + int kComponents, const int *kPartFilters, + const float *b, float scoreThreshold, + CvPoint **points, CvPoint **oppPoints, + float **score, int *kPoints) +{ + int error = 0; + int i, j, s, f, componentIndex; + unsigned int maxXBorder, maxYBorder; + CvPoint **pointsArr, **oppPointsArr, ***partsDisplacementArr; + float **scoreArr; + int *kPointsArr, **levelsArr; + + // Allocation memory + pointsArr = (CvPoint **)malloc(sizeof(CvPoint *) * kComponents); + oppPointsArr = (CvPoint **)malloc(sizeof(CvPoint *) * kComponents); + scoreArr = (float **)malloc(sizeof(float *) * kComponents); + kPointsArr = (int *)malloc(sizeof(int) * kComponents); + levelsArr = (int **)malloc(sizeof(int *) * kComponents); + partsDisplacementArr = (CvPoint ***)malloc(sizeof(CvPoint **) * kComponents); + + // Getting maximum filter dimensions + error = getMaxFilterDims(filters, kComponents, kPartFilters, &maxXBorder, &maxYBorder); + componentIndex = 0; + *kPoints = 0; + // For each component perform searching + for (i = 0; i < kComponents; i++) + { + searchObjectThreshold(H, &(filters[componentIndex]), kPartFilters[i], + b[i], maxXBorder, maxYBorder, scoreThreshold, + &(pointsArr[i]), &(levelsArr[i]), &(kPointsArr[i]), + &(scoreArr[i]), &(partsDisplacementArr[i])); + estimateBoxes(pointsArr[i], levelsArr[i], kPointsArr[i], + filters[componentIndex]->sizeX, filters[componentIndex]->sizeY, &(oppPointsArr[i])); + componentIndex += (kPartFilters[i] + 1); + *kPoints += kPointsArr[i]; + } + + *points = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + *oppPoints = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + *score = (float *)malloc(sizeof(float) * (*kPoints)); + s = 0; + for (i = 0; i < kComponents; i++) + { + f = s + kPointsArr[i]; + for (j = s; j < f; j++) + { + (*points)[j].x = pointsArr[i][j - s].x; + (*points)[j].y = pointsArr[i][j - s].y; + (*oppPoints)[j].x = oppPointsArr[i][j - s].x; + (*oppPoints)[j].y = oppPointsArr[i][j - s].y; + (*score)[j] = scoreArr[i][j - s]; + } + s = f; + } + + // Release allocated memory + for (i = 0; i < kComponents; i++) + { + free(pointsArr[i]); + free(oppPointsArr[i]); + free(scoreArr[i]); + free(levelsArr[i]); + for (j = 0; j < kPointsArr[i]; j++) + { + free(partsDisplacementArr[i][j]); + } + free(partsDisplacementArr[i]); + } + free(pointsArr); + free(oppPointsArr); + free(scoreArr); + free(kPointsArr); + free(levelsArr); + free(partsDisplacementArr); + return LATENT_SVM_OK; +} diff --git a/modules/objdetect/src/latentsvmdetector.cpp b/modules/objdetect/src/latentsvmdetector.cpp new file mode 100644 index 0000000000..f7dcd8fa5d --- /dev/null +++ b/modules/objdetect/src/latentsvmdetector.cpp @@ -0,0 +1,134 @@ +#include "precomp.hpp" +#include "_lsvmparser.h" +#include "_matching.h" + +/* +// load trained detector from a file +// +// API +// CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename); +// INPUT +// filename - path to the file containing the parameters of + - trained Latent SVM detector +// OUTPUT +// trained Latent SVM detector in internal representation +*/ +CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename) +{ + CvLatentSvmDetector* detector = 0; + filterObject** filters = 0; + int kFilters = 0; + int kComponents = 0; + int* kPartFilters = 0; + float* b = 0; + float scoreThreshold = 0.f; + + loadModel(filename, &filters, &kFilters, &kComponents, &kPartFilters, &b, &scoreThreshold); + + detector = (CvLatentSvmDetector*)malloc(sizeof(CvLatentSvmDetector)); + detector->filters = filters; + detector->b = b; + detector->num_components = kComponents; + detector->num_filters = kFilters; + detector->num_part_filters = kPartFilters; + detector->score_threshold = scoreThreshold; + + return detector; +} + +/* +// release memory allocated for CvLatentSvmDetector structure +// +// API +// void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); +// INPUT +// detector - CvLatentSvmDetector structure to be released +// OUTPUT +*/ +void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector) +{ + free((*detector)->b); + free((*detector)->num_part_filters); + for (int i = 0; i < (*detector)->num_filters; i++) + { + free((*detector)->filters[i]->H); + free((*detector)->filters[i]); + } + free((*detector)->filters); + free((*detector)); + *detector = 0; +} + +/* +// find rectangular regions in the given image that are likely +// to contain objects and corresponding confidence levels +// +// API +// CvSeq* cvLatentSvmDetectObjects(const IplImage* image, +// CvLatentSvmDetector* detector, +// CvMemStorage* storage, +// float overlap_threshold = 0.5f); +// INPUT +// image - image to detect objects in +// detector - Latent SVM detector in internal representation +// storage - memory storage to store the resultant sequence +// of the object candidate rectangles +// overlap_threshold - threshold for the non-maximum suppression algorithm [here will be the reference to original paper] +// OUTPUT +// sequence of detected objects (bounding boxes and confidence levels stored in CvObjectDetection structures) +*/ +CvSeq* cvLatentSvmDetectObjects(IplImage* image, + CvLatentSvmDetector* detector, + CvMemStorage* storage, + float overlap_threshold) +{ + featurePyramid *H = 0; + CvPoint *points = 0, *oppPoints = 0; + int kPoints = 0; + float *score = 0; + unsigned int maxXBorder = 0, maxYBorder = 0; + int numBoxesOut = 0; + CvPoint *pointsOut = 0; + CvPoint *oppPointsOut = 0; + float *scoreOut = 0; + CvSeq* result_seq = 0; + + cvConvertImage(image, image, CV_CVTIMG_SWAP_RB); + // Getting maximum filter dimensions + getMaxFilterDims((const filterObject**)(detector->filters), detector->num_components, detector->num_part_filters, &maxXBorder, &maxYBorder); + // Create feature pyramid with nullable border + H = createFeaturePyramidWithBorder(image, maxXBorder, maxYBorder); + // Search object + searchObjectThresholdSomeComponents(H, (const filterObject**)(detector->filters), detector->num_components, + detector->num_part_filters, detector->b, detector->score_threshold, + &points, &oppPoints, &score, &kPoints); + // Clipping boxes + clippingBoxes(image->width, image->height, points, kPoints); + clippingBoxes(image->width, image->height, oppPoints, kPoints); + // NMS procedure + nonMaximumSuppression(kPoints, points, oppPoints, score, overlap_threshold, + &numBoxesOut, &pointsOut, &oppPointsOut, &scoreOut); + + result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvObjectDetection), storage ); + + for (int i = 0; i < numBoxesOut; i++) + { + CvObjectDetection detection = {{0, 0, 0, 0}, 0}; + detection.score = scoreOut[i]; + CvRect bounding_box = {0, 0, 0, 0}; + bounding_box.x = pointsOut[i].x; + bounding_box.y = pointsOut[i].y; + bounding_box.width = oppPointsOut[i].x - pointsOut[i].x; + bounding_box.height = oppPointsOut[i].y - pointsOut[i].y; + detection.rect = bounding_box; + cvSeqPush(result_seq, &detection); + } + cvConvertImage(image, image, CV_CVTIMG_SWAP_RB); + + freeFeaturePyramidObject(&H); + free(points); + free(oppPoints); + free(score); + + return result_seq; +} \ No newline at end of file diff --git a/modules/objdetect/src/lsvmparser.cpp b/modules/objdetect/src/lsvmparser.cpp new file mode 100644 index 0000000000..a9eeac6f46 --- /dev/null +++ b/modules/objdetect/src/lsvmparser.cpp @@ -0,0 +1,800 @@ +#include +#include "string.h" +#include "_lsvmparser.h" + +int isMODEL (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return MODEL; + if(strcmp(etag, str) == 0)return EMODEL; + return 0; +} +int isP (char *str){ + char stag [] = "

"; + char etag [] = "

"; + if(strcmp(stag, str) == 0)return P; + if(strcmp(etag, str) == 0)return EP; + return 0; +} +int isSCORE (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return SCORE; + if(strcmp(etag, str) == 0)return ESCORE; + return 0; +} +int isCOMP (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return COMP; + if(strcmp(etag, str) == 0)return ECOMP; + return 0; +} +int isRFILTER (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return RFILTER; + if(strcmp(etag, str) == 0)return ERFILTER; + return 0; +} +int isPFILTERs (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return PFILTERs; + if(strcmp(etag, str) == 0)return EPFILTERs; + return 0; +} +int isPFILTER (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return PFILTER; + if(strcmp(etag, str) == 0)return EPFILTER; + return 0; +} +int isSIZEX (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return SIZEX; + if(strcmp(etag, str) == 0)return ESIZEX; + return 0; +} +int isSIZEY (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return SIZEY; + if(strcmp(etag, str) == 0)return ESIZEY; + return 0; +} +int isWEIGHTS (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return WEIGHTS; + if(strcmp(etag, str) == 0)return EWEIGHTS; + return 0; +} +int isV (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return TAGV; + if(strcmp(etag, str) == 0)return ETAGV; + return 0; +} +int isVx (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Vx; + if(strcmp(etag, str) == 0)return EVx; + return 0; +} +int isVy (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Vy; + if(strcmp(etag, str) == 0)return EVy; + return 0; +} +int isD (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return TAGD; + if(strcmp(etag, str) == 0)return ETAGD; + return 0; +} +int isDx (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Dx; + if(strcmp(etag, str) == 0)return EDx; + return 0; +} +int isDy (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Dy; + if(strcmp(etag, str) == 0)return EDy; + return 0; +} +int isDxx (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Dxx; + if(strcmp(etag, str) == 0)return EDxx; + return 0; +} +int isDyy (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return Dyy; + if(strcmp(etag, str) == 0)return EDyy; + return 0; +} +int isB (char *str){ + char stag [] = ""; + char etag [] = ""; + if(strcmp(stag, str) == 0)return BTAG; + if(strcmp(etag, str) == 0)return EBTAG; + return 0; +} + +int getTeg(char *str){ + int sum = 0; + sum = isMODEL (str)+ + isP (str)+ + isSCORE (str)+ + isCOMP (str)+ + isRFILTER (str)+ + isPFILTERs (str)+ + isPFILTER (str)+ + isSIZEX (str)+ + isSIZEY (str)+ + isWEIGHTS (str)+ + isV (str)+ + isVx (str)+ + isVy (str)+ + isD (str)+ + isDx (str)+ + isDy (str)+ + isDxx (str)+ + isDyy (str)+ + isB (str); + + return sum; +} + +void addFilter(filterObject *** model, int *last, int *max){ + filterObject ** nmodel; + int i; + (*last) ++; + if((*last) >= (*max)){ + (*max) += 10; + nmodel = (filterObject **)malloc(sizeof(filterObject *) * (*max)); + for(i = 0; i < *last; i++){ + nmodel[i] = (* model)[i]; + } + free(* model); + (*model) = nmodel; + } + (*model) [(*last)] = (filterObject *)malloc(sizeof(filterObject)); +} + +void parserRFilter (FILE * xmlf, int p, filterObject * model, float *b){ + int st = 0; + int sizeX, sizeY; + int tag; + int tagVal; + char ch; + int i,j,ii; + char buf[1024]; + char tagBuf[1024]; + double *data; + //printf("\n"); + + model->V.x = 0; + model->V.y = 0; + model->V.l = 0; + model->fineFunction[0] = 0.0; + model->fineFunction[1] = 0.0; + model->fineFunction[2] = 0.0; + model->fineFunction[3] = 0.0; + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == ERFILTER){ + //printf("\n"); + return; + } + if(tagVal == SIZEX){ + st = 1; + i = 0; + } + if(tagVal == ESIZEX){ + st = 0; + buf[i] = '\0'; + sizeX = atoi(buf); + model->sizeX = sizeX; + //printf("%d\n", sizeX); + } + if(tagVal == SIZEY){ + st = 1; + i = 0; + } + if(tagVal == ESIZEY){ + st = 0; + buf[i] = '\0'; + sizeY = atoi(buf); + model->sizeY = sizeY; + //printf("%d\n", sizeY); + } + if(tagVal == WEIGHTS){ + data = (double *)malloc( sizeof(double) * p * sizeX * sizeY); + fread(data, sizeof(double), p * sizeX * sizeY, xmlf); + model->H = (float *)malloc(sizeof(float)* p * sizeX * sizeY); + for(ii = 0; ii < p * sizeX * sizeY; ii++){ + model->H[ii] = (float)data[ii]; + } + free(data); + } + if(tagVal == EWEIGHTS){ + //printf("WEIGHTS OK\n"); + } + if(tagVal == BTAG){ + st = 1; + i = 0; + } + if(tagVal == EBTAG){ + st = 0; + buf[i] = '\0'; + *b =(float) atof(buf); + //printf("%f\n", *b); + } + + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} + +void parserV (FILE * xmlf, int p, filterObject * model){ + int st = 0; + int tag; + int tagVal; + char ch; + int i,j; + char buf[1024]; + char tagBuf[1024]; + //printf(" \n"); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == ETAGV){ + //printf(" \n"); + return; + } + if(tagVal == Vx){ + st = 1; + i = 0; + } + if(tagVal == EVx){ + st = 0; + buf[i] = '\0'; + model->V.x = atoi(buf); + //printf(" %d\n", model->V.x); + } + if(tagVal == Vy){ + st = 1; + i = 0; + } + if(tagVal == EVy){ + st = 0; + buf[i] = '\0'; + model->V.y = atoi(buf); + //printf(" %d\n", model->V.y); + } + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} +void parserD (FILE * xmlf, int p, filterObject * model){ + int st = 0; + int tag; + int tagVal; + char ch; + int i,j; + char buf[1024]; + char tagBuf[1024]; + //printf(" \n"); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == ETAGD){ + //printf(" \n"); + return; + } + if(tagVal == Dx){ + st = 1; + i = 0; + } + if(tagVal == EDx){ + st = 0; + buf[i] = '\0'; + + model->fineFunction[0] = (float)atof(buf); + //printf(" %f\n", model->fineFunction[0]); + } + if(tagVal == Dy){ + st = 1; + i = 0; + } + if(tagVal == EDy){ + st = 0; + buf[i] = '\0'; + + model->fineFunction[1] = (float)atof(buf); + //printf(" %f\n", model->fineFunction[1]); + } + if(tagVal == Dxx){ + st = 1; + i = 0; + } + if(tagVal == EDxx){ + st = 0; + buf[i] = '\0'; + + model->fineFunction[2] = (float)atof(buf); + //printf(" %f\n", model->fineFunction[2]); + } + if(tagVal == Dyy){ + st = 1; + i = 0; + } + if(tagVal == EDyy){ + st = 0; + buf[i] = '\0'; + + model->fineFunction[3] = (float)atof(buf); + //printf(" %f\n", model->fineFunction[3]); + } + + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} + +void parserPFilter (FILE * xmlf, int p, int N_path, filterObject * model){ + int st = 0; + int sizeX, sizeY; + int tag; + int tagVal; + char ch; + int i,j, ii; + char buf[1024]; + char tagBuf[1024]; + double *data; + //printf(" (%d)\n", N_path); + + model->V.x = 0; + model->V.y = 0; + model->V.l = 0; + model->fineFunction[0] = 0.0f; + model->fineFunction[1] = 0.0f; + model->fineFunction[2] = 0.0f; + model->fineFunction[3] = 0.0f; + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == EPFILTER){ + //printf("\n"); + return; + } + + if(tagVal == TAGV){ + parserV(xmlf, p, model); + } + if(tagVal == TAGD){ + parserD(xmlf, p, model); + } + if(tagVal == SIZEX){ + st = 1; + i = 0; + } + if(tagVal == ESIZEX){ + st = 0; + buf[i] = '\0'; + sizeX = atoi(buf); + model->sizeX = sizeX; + //printf("%d\n", sizeX); + } + if(tagVal == SIZEY){ + st = 1; + i = 0; + } + if(tagVal == ESIZEY){ + st = 0; + buf[i] = '\0'; + sizeY = atoi(buf); + model->sizeY = sizeY; + //printf("%d\n", sizeY); + } + if(tagVal == WEIGHTS){ + data = (double *)malloc( sizeof(double) * p * sizeX * sizeY); + fread(data, sizeof(double), p * sizeX * sizeY, xmlf); + model->H = (float *)malloc(sizeof(float)* p * sizeX * sizeY); + for(ii = 0; ii < p * sizeX * sizeY; ii++){ + model->H[ii] = (float)data[ii]; + } + free(data); + } + if(tagVal == EWEIGHTS){ + //printf("WEIGHTS OK\n"); + } + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} +void parserPFilterS (FILE * xmlf, int p, filterObject *** model, int *last, int *max){ + int st = 0; + int N_path = 0; + int tag; + int tagVal; + char ch; + int i,j; + char buf[1024]; + char tagBuf[1024]; + //printf("\n"); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == EPFILTERs){ + //printf("\n"); + return; + } + if(tagVal == PFILTER){ + addFilter(model, last, max); + parserPFilter (xmlf, p, N_path, (*model)[*last]); + N_path++; + } + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} +void parserComp (FILE * xmlf, int p, int *N_comp, filterObject *** model, float *b, int *last, int *max){ + int st = 0; + int tag; + int tagVal; + char ch; + int i,j; + char buf[1024]; + char tagBuf[1024]; + //printf(" %d\n", *N_comp); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == ECOMP){ + (*N_comp) ++; + return; + } + if(tagVal == RFILTER){ + addFilter(model, last, max); + parserRFilter (xmlf, p, (*model)[*last],b); + } + if(tagVal == PFILTERs){ + parserPFilterS (xmlf, p, model, last, max); + } + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} +void parserModel(FILE * xmlf, filterObject *** model, int *last, int *max, int **comp, float **b, int *count, float * score){ + int p = 0; + int N_comp = 0; + int * cmp; + float *bb; + int st = 0; + int tag; + int tagVal; + char ch; + int i,j, ii = 0; + char buf[1024]; + char tagBuf[1024]; + + //printf("\n"); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + + tagVal = getTeg(tagBuf); + + if(tagVal == EMODEL){ + //printf("\n"); + for(ii = 0; ii <= *last; ii++){ + (*model)[ii]->p = p; + (*model)[ii]->xp = 9; + } + * count = N_comp; + return; + } + if(tagVal == COMP){ + if(N_comp == 0){ + cmp = (int *)malloc(sizeof(int)); + bb = (float *)malloc(sizeof(float)); + * comp = cmp; + * b = bb; + * count = N_comp + 1; + } else { + cmp = (int *)malloc(sizeof(int) * (N_comp + 1)); + bb = (float *)malloc(sizeof(float) * (N_comp + 1)); + for(ii = 0; ii < N_comp; ii++){ + cmp[i] = (* comp)[ii]; + bb [i] = (* b )[ii]; + } + free(* comp); + free(* b ); + * comp = cmp; + * b = bb; + * count = N_comp + 1; + } + parserComp(xmlf, p, &N_comp, model, &((*b)[N_comp]), last, max); + cmp[N_comp - 1] = *last; + } + if(tagVal == P){ + st = 1; + i = 0; + } + if(tagVal == EP){ + st = 0; + buf[i] = '\0'; + p = atoi(buf); + //printf("

%d

\n", p); + } + if(tagVal == SCORE){ + st = 1; + i = 0; + } + if(tagVal == ESCORE){ + st = 0; + buf[i] = '\0'; + *score = (float)atof(buf); + //printf("%f\n", score); + } + tag = 0; + i = 0; + }else{ + if((tag == 0)&& (st == 1)){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} + +void LSVMparser(const char * filename, filterObject *** model, int *last, int *max, int **comp, float **b, int *count, float * score){ + int st = 0; + int tag; + char ch; + int i,j; + FILE *xmlf; + char buf[1024]; + char tagBuf[1024]; + + (*max) = 10; + (*last) = -1; + (*model) = (filterObject ** )malloc((sizeof(filterObject * )) * (*max)); + + //printf("parse : %s\n", filename); + xmlf = fopen(filename, "rb"); + + i = 0; + j = 0; + st = 0; + tag = 0; + while(!feof(xmlf)){ + ch = fgetc( xmlf ); + if(ch == '<'){ + tag = 1; + j = 1; + tagBuf[j - 1] = ch; + }else { + if(ch == '>'){ + tag = 0; + i = 0; + tagBuf[j ] = ch; + tagBuf[j + 1] = '\0'; + if(getTeg(tagBuf) == MODEL){ + parserModel(xmlf, model, last, max, comp, b, count, score); + } + }else{ + if(tag == 0){ + buf[i] = ch; i++; + }else{ + tagBuf[j] = ch; j++; + } + } + } + } +} + +int loadModel( + // Входные параметры + const char *modelPath,// - путь до файла с моделью + + // Выходные параметры + filterObject ***filters,// - массив указателей на фильтры компонент + int *kFilters, //- общее количество фильтров во всех моделях + int *kComponents, //- количество компонент + int **kPartFilters, //- массив, содержащий количество точных фильтров в каждой компоненте + float **b, //- массив линейных членов в оценочной функции + float *scoreThreshold){ //- порог для score) + int last; + int max; + int *comp; + int count; + int i; + float score; + //printf("start_parse\n\n"); + + LSVMparser(modelPath, filters, &last, &max, &comp, b, &count, &score); + (*kFilters) = last + 1; + (*kComponents) = count; + (*scoreThreshold) = (float) score; + + (*kPartFilters) = (int *)malloc(sizeof(int) * count); + + for(i = 1; i < count;i++){ + (*kPartFilters)[i] = (comp[i] - comp[i - 1]) - 1; + } + (*kPartFilters)[0] = comp[0]; + + //printf("end_parse\n"); + return 0; +} \ No newline at end of file diff --git a/modules/objdetect/src/matching.cpp b/modules/objdetect/src/matching.cpp new file mode 100644 index 0000000000..c8634abda8 --- /dev/null +++ b/modules/objdetect/src/matching.cpp @@ -0,0 +1,1462 @@ +#include "_matching.h" +#include + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* +// Function for convolution computation +// +// INPUT +// Fi - filter object +// map - feature map +// OUTPUT +// f - the convolution +// RESULT +// Error status +*/ +int convolution(const filterObject *Fi, const featureMap *map, float *f) +{ + int n1, m1, n2, m2, p, size, diff1, diff2; + int i1, i2, j1, j2, k; + + n1 = map->sizeY; + m1 = map->sizeX; + n2 = Fi->sizeY; + m2 = Fi->sizeX; + p = map->p; + if (n1 < n2 || m1 < m2) + { + return FILTER_OUT_OF_BOUNDARIES; + } + + // Computation number of positions for the filter + diff1 = n1 - n2 + 1; + diff2 = m1 - m2 + 1; + size = diff1 * diff2; + + for (i1 = 0; i1 < diff1; i1++) + { + for (j1 = 0; j1 < diff2; j1++) + { + f[i1 * diff2 + j1] = 0.0; + for (i2 = 0; i2 < n2; i2++) + { + for (j2 = 0; j2 < m2; j2++) + { + for (k = 0; k < p; k++) + { + f[i1 * diff2 + j1] += map->Map[(i1 + i2) * m1 * p + + (j1 + j2) * p + k] * + Fi->H[(i2 * m2 + j2) * p + k]; + } + } + } + } + } + return LATENT_SVM_OK; +} + +/* +// Computation multiplication of FFT images +// +// API +// int fftImagesMulti(float *fftImage1, float *fftImage2, int numRows, int numColls, + float *multi); +// INPUT +// fftImage1 - first fft image +// fftImage2 - second fft image +// (numRows, numColls) - image dimesions +// OUTPUT +// multi - multiplication +// RESULT +// Error status +*/ +int fftImagesMulti(float *fftImage1, float *fftImage2, int numRows, int numColls, + float *multi) +{ + int i, index, size; + size = numRows * numColls; + for (i = 0; i < size; i++) + { + index = 2 * i; + multi[index] = fftImage1[index] * fftImage2[index] - + fftImage1[index + 1] * fftImage2[index + 1]; + multi[index + 1] = fftImage1[index] * fftImage2[index + 1] + + fftImage1[index + 1] * fftImage2[index]; + } + return LATENT_SVM_OK; +} + +/* +// Turnover filter matrix for the single feature +// +// API +// int rot2PI(float *filter, int dimX, int dimY, float *rot2PIFilter, + int p, int shift); +// INPUT +// filter - filter weight matrix +// (dimX, dimY) - dimension of filter matrix +// p - number of features +// shift - number of feature (or channel) +// OUTPUT +// rot2PIFilter - rotated matrix +// RESULT +// Error status +*/ +int rot2PI(float *filter, int dimX, int dimY, float *rot2PIFilter, + int p, int shift) +{ + int i, size; + size = dimX * dimY; + for (i = 0; i < size; i++) + { + rot2PIFilter[i] = filter[(size - i - 1) * p + shift]; + } + return LATENT_SVM_OK; +} + +/* +// Addition nullable bars to the dimension of feature map (single feature) +// +// API +// int addNullableBars(float *rot2PIFilter, int dimX, int dimY, + float *newFilter, int newDimX, int newDimY); +// INPUT +// rot2PIFilter - filter matrix for the single feature that was rotated +// (dimX, dimY) - dimension rot2PIFilter +// (newDimX, newDimY)- dimension of feature map for the single feature +// OUTPUT +// newFilter - filter matrix with nullable bars +// RESULT +// Error status +*/ +int addNullableBars(float *rot2PIFilter, int dimX, int dimY, + float *newFilter, int newDimX, int newDimY) +{ + int size, i, j; + size = newDimX * newDimY; + for (i = 0; i < size; i++) + { + newFilter[2 * i] = 0.0; + newFilter[2 * i + 1] = 0.0; + } + for (i = 0; i < dimY; i++) + { + for (j = 0; j < dimX; j++) + { + newFilter[2 * (i * newDimX + j)] = rot2PIFilter[i * dimX + j]; + } + } + return LATENT_SVM_OK; +} + +/* +// Computation FFT image for filter object +// +// API +// int getFFTImageFilterObject(const filterObject *filter, + int mapDimX, int mapDimY, + fftImage **image); +// INPUT +// filter - filter object +// (mapDimX, mapDimY)- dimension of feature map +// OUTPUT +// image - fft image +// RESULT +// Error status +*/ +int getFFTImageFilterObject(const filterObject *filter, + int mapDimX, int mapDimY, + fftImage **image) +{ + unsigned int i, mapSize, filterSize; + int res; + float *newFilter, *rot2PIFilter; + + filterSize = filter->sizeX * filter->sizeY; + mapSize = mapDimX * mapDimY; + newFilter = (float *)malloc(sizeof(float) * (2 * mapSize)); + rot2PIFilter = (float *)malloc(sizeof(float) * filterSize); + res = allocFFTImage(image, filter->p, mapDimX, mapDimY); + if (res != LATENT_SVM_OK) + { + return res; + } + for (i = 0; i < filter->p; i++) + { + rot2PI(filter->H, filter->sizeX, filter->sizeY, rot2PIFilter, filter->p, i); + addNullableBars(rot2PIFilter, filter->sizeX, filter->sizeY, + newFilter, mapDimX, mapDimY); + fft2d(newFilter, (*image)->channels[i], mapDimY, mapDimX); + } + free(newFilter); + free(rot2PIFilter); + return LATENT_SVM_OK; +} + +/* +// Computation FFT image for feature map +// +// API +// int getFFTImageFeatureMap(const featureMap *map, fftImage **image); +// INPUT +// OUTPUT +// RESULT +// Error status +*/ +int getFFTImageFeatureMap(const featureMap *map, fftImage **image) +{ + int i, j, size; + float *buf; + allocFFTImage(image, map->p, map->sizeX, map->sizeY); + size = map->sizeX * map->sizeY; + buf = (float *)malloc(sizeof(float) * (2 * size)); + for (i = 0; i < map->p; i++) + { + for (j = 0; j < size; j++) + { + buf[2 * j] = map->Map[j * map->p + i]; + buf[2 * j + 1] = 0.0; + } + fft2d(buf, (*image)->channels[i], map->sizeY, map->sizeX); + } + free(buf); + return LATENT_SVM_OK; +} + +/* +// Function for convolution computation using FFT +// +// API +// int convFFTConv2d(const fftImage *featMapImage, const fftImage *filterImage, + int filterDimX, int filterDimY, float **conv); +// INPUT +// featMapImage - feature map image +// filterImage - filter image +// (filterDimX,filterDimY) - filter dimension +// OUTPUT +// conv - the convolution +// RESULT +// Error status +*/ +int convFFTConv2d(const fftImage *featMapImage, const fftImage *filterImage, + int filterDimX, int filterDimY, float **conv) +{ + int i, j, size, diffX, diffY, index; + float *imagesMult, *imagesMultRes, *fconv; + size = 2 * featMapImage->dimX * featMapImage->dimY; + imagesMult = (float *)malloc(sizeof(float) * size); + imagesMultRes = (float *)malloc(sizeof(float) * size); + fftImagesMulti(featMapImage->channels[0], filterImage->channels[0], + featMapImage->dimY, featMapImage->dimX, imagesMultRes); + for (i = 1; (i < featMapImage->p) && (i < filterImage->p); i++) + { + fftImagesMulti(featMapImage->channels[i],filterImage->channels[i], + featMapImage->dimY, featMapImage->dimX, imagesMult); + for (j = 0; j < size; j++) + { + imagesMultRes[j] += imagesMult[j]; + } + } + fconv = (float *)malloc(sizeof(float) * size); + fftInverse2d(imagesMultRes, fconv, featMapImage->dimY, featMapImage->dimX); + diffX = featMapImage->dimX - filterDimX + 1; + diffY = featMapImage->dimY - filterDimY + 1; + *conv = (float *)malloc(sizeof(float) * (diffX * diffY)); + for (i = 0; i < diffY; i++) + { + for (j = 0; j < diffX; j++) + { + index = (i + filterDimY - 1) * featMapImage->dimX + + (j + filterDimX - 1); + (*conv)[i * diffX + j] = fconv[2 * index]; + } + } + free(imagesMult); + free(imagesMultRes); + free(fconv); + return LATENT_SVM_OK; +} + +/* +// Computation objective function D according the original paper +// +// API +// int filterDispositionLevel(const filterObject *Fi, const featurePyramid *H, + int level, float **scoreFi, + int **pointsX, int **pointsY); +// INPUT +// Fi - filter object (weights and coefficients of penalty + function that are used in this routine) +// H - feature pyramid +// level - level number +// OUTPUT +// scoreFi - values of distance transform on the level at all positions +// (pointsX, pointsY)- positions that correspond to the maximum value + of distance transform at all grid nodes +// RESULT +// Error status +*/ +int filterDispositionLevel(const filterObject *Fi, const featureMap *pyramid, + float **scoreFi, + int **pointsX, int **pointsY) +{ + int n1, m1, n2, m2, p, size, diff1, diff2; + float *f; + int i1, j1; + int res; + + n1 = pyramid->sizeY; + m1 = pyramid->sizeX; + n2 = Fi->sizeY; + m2 = Fi->sizeX; + p = pyramid->p; + (*scoreFi) = NULL; + (*pointsX) = NULL; + (*pointsY) = NULL; + + // Processing the situation when part filter goes + // beyond the boundaries of the block set + if (n1 < n2 || m1 < m2) + { + return FILTER_OUT_OF_BOUNDARIES; + } /* if (n1 < n2 || m1 < m2) */ + + // Computation number of positions for the filter + diff1 = n1 - n2 + 1; + diff2 = m1 - m2 + 1; + size = diff1 * diff2; + + // Allocation memory for additional array (must be free in this function) + f = (float *)malloc(sizeof(float) * size); + // Allocation memory for arrays for saving decisions + (*scoreFi) = (float *)malloc(sizeof(float) * size); + (*pointsX) = (int *)malloc(sizeof(int) * size); + (*pointsY) = (int *)malloc(sizeof(int) * size); + + // Consruction values of the array f + // (a dot product vectors of feature map and weights of the filter) + res = convolution(Fi, pyramid, f); + if (res != LATENT_SVM_OK) + { + free(f); + free(*scoreFi); + free(*pointsX); + free(*pointsY); + return res; + } + + // TODO: necessary to change + for (i1 = 0; i1 < diff1; i1++) + { + for (j1 = 0; j1 < diff2; j1++) + { + f[i1 * diff2 + j1] *= (-1); + } + } + + // Decision of the general distance transform task + DistanceTransformTwoDimensionalProblem(f, diff1, diff2, Fi->fineFunction, + (*scoreFi), (*pointsX), (*pointsY)); + + // Release allocated memory + free(f); + return LATENT_SVM_OK; +} + +/* +// Computation objective function D according the original paper using FFT +// +// API +// int filterDispositionLevelFFT(const filterObject *Fi, const fftImage *featMapImage, + float **scoreFi, + int **pointsX, int **pointsY); +// INPUT +// Fi - filter object (weights and coefficients of penalty + function that are used in this routine) +// featMapImage - FFT image of feature map +// OUTPUT +// scoreFi - values of distance transform on the level at all positions +// (pointsX, pointsY)- positions that correspond to the maximum value + of distance transform at all grid nodes +// RESULT +// Error status +*/ +int filterDispositionLevelFFT(const filterObject *Fi, const fftImage *featMapImage, + float **scoreFi, + int **pointsX, int **pointsY) +{ + int n1, m1, n2, m2, p, size, diff1, diff2; + float *f; + int i1, j1; + int res; + fftImage *filterImage; + + n1 = featMapImage->dimY; + m1 = featMapImage->dimX; + n2 = Fi->sizeY; + m2 = Fi->sizeX; + p = featMapImage->p; + (*scoreFi) = NULL; + (*pointsX) = NULL; + (*pointsY) = NULL; + + // Processing the situation when part filter goes + // beyond the boundaries of the block set + if (n1 < n2 || m1 < m2) + { + return FILTER_OUT_OF_BOUNDARIES; + } /* if (n1 < n2 || m1 < m2) */ + + // Computation number of positions for the filter + diff1 = n1 - n2 + 1; + diff2 = m1 - m2 + 1; + size = diff1 * diff2; + + // Allocation memory for arrays for saving decisions + (*scoreFi) = (float *)malloc(sizeof(float) * size); + (*pointsX) = (int *)malloc(sizeof(int) * size); + (*pointsY) = (int *)malloc(sizeof(int) * size); + + // create filter image + getFFTImageFilterObject(Fi, featMapImage->dimX, featMapImage->dimY, &filterImage); + + // Consruction values of the array f + // (a dot product vectors of feature map and weights of the filter) + res = convFFTConv2d(featMapImage, filterImage, Fi->sizeX, Fi->sizeY, &f); + if (res != LATENT_SVM_OK) + { + free(f); + free(*scoreFi); + free(*pointsX); + free(*pointsY); + return res; + } + + // TODO: necessary to change + for (i1 = 0; i1 < diff1; i1++) + { + for (j1 = 0; j1 < diff2; j1++) + { + f[i1 * diff2 + j1] *= (-1); + } + } + + // Decision of the general distance transform task + DistanceTransformTwoDimensionalProblem(f, diff1, diff2, Fi->fineFunction, + (*scoreFi), (*pointsX), (*pointsY)); + + // Release allocated memory + free(f); + freeFFTImage(&filterImage); + return LATENT_SVM_OK; +} + +/* +// Computation border size for feature map +// +// API +// int computeBorderSize(int maxXBorder, int maxYBorder, int *bx, int *by); +// INPUT +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// bx - border size (X-direction) +// by - border size (Y-direction) +// RESULT +// Error status +*/ +int computeBorderSize(int maxXBorder, int maxYBorder, int *bx, int *by) +{ + *bx = (int)ceilf(((float) maxXBorder) / 2.0f + 1.0f); + *by = (int)ceilf(((float) maxYBorder) / 2.0f + 1.0f); + return LATENT_SVM_OK; +} + +/* +// Addition nullable border to the feature map +// +// API +// int addNullableBorder(featureMap *map, int bx, int by); +// INPUT +// map - feature map +// bx - border size (X-direction) +// by - border size (Y-direction) +// OUTPUT +// RESULT +// Error status +*/ +int addNullableBorder(featureMap *map, int bx, int by) +{ + int sizeX, sizeY, i, j, k; + float *new_map; + sizeX = map->sizeX + 2 * bx; + sizeY = map->sizeY + 2 * by; + new_map = (float *)malloc(sizeof(float) * sizeX * sizeY * map->p); + for (i = 0; i < sizeX * sizeY * map->p; i++) + { + new_map[i] = 0.0; + } + for (i = by; i < map->sizeY + by; i++) + { + for (j = bx; j < map->sizeX + bx; j++) + { + for (k = 0; k < map->p; k++) + { + new_map[(i * sizeX + j) * map->p + k] = + map->Map[((i - by) * map->sizeX + j - bx) * map->p + k]; + } + } + } + map->sizeX = sizeX; + map->sizeY = sizeY; + free(map->Map); + map->Map = new_map; + return LATENT_SVM_OK; +} + +featureMap* featureMapBorderPartFilter(featureMap *map, + int maxXBorder, int maxYBorder) +{ + int bx, by; + int sizeX, sizeY, i, j, k; + featureMap *new_map; + + computeBorderSize(maxXBorder, maxYBorder, &bx, &by); + sizeX = map->sizeX + 2 * bx; + sizeY = map->sizeY + 2 * by; + allocFeatureMapObject(&new_map, sizeX, sizeY, map->p, map->xp); + for (i = 0; i < sizeX * sizeY * map->p; i++) + { + new_map->Map[i] = 0.0; + } + for (i = by; i < map->sizeY + by; i++) + { + for (j = bx; j < map->sizeX + bx; j++) + { + for (k = 0; k < map->p; k++) + { + new_map->Map[(i * sizeX + j) * map->p + k] = + map->Map[((i - by) * map->sizeX + j - bx) * map->p + k]; + } + } + } + return new_map; +} + +/* +// Computation the maximum of the score function at the level +// +// API +// int maxFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float *score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// level - feature pyramid level for computation maximum score +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// score - the maximum of the score function at the level +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int maxFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float *score, CvPoint **points, + int *kPoints, CvPoint ***partsDisplacement) +{ + int i, j, k, dimX, dimY, nF0, mF0, p; + int diff1, diff2, index, last, partsLevel; + filterDisposition **disposition; + float *f; + float *scores; + float sumScorePartDisposition, maxScore; + int res; + featureMap *map; +#ifdef FFT_CONV + fftImage *rootFilterImage, *mapImage; +#else +#endif + + /* + // DEBUG variables + FILE *file; + char *tmp; + char buf[40] = "..\\Data\\score\\score", buf1[10] = ".csv"; + tmp = (char *)malloc(sizeof(char) * 80); + itoa(level, tmp, 10); + strcat(tmp, buf1); + //*/ + + // Feature map matrix dimension on the level + dimX = H->pyramid[level]->sizeX; + dimY = H->pyramid[level]->sizeY; + + // Number of features + p = H->pyramid[level]->p; + + // Getting dimension of root filter + nF0 = all_F[0]->sizeY; + mF0 = all_F[0]->sizeX; + // Processing the situation when root filter goes + // beyond the boundaries of the block set + if (nF0 > dimY || mF0 > dimX) + { + return LATENT_SVM_FAILED_SUPERPOSITION; + } + + diff1 = dimY - nF0 + 1; + diff2 = dimX - mF0 + 1; + + // Allocation memory for saving values of function D + // on the level for each part filter + disposition = (filterDisposition **)malloc(sizeof(filterDisposition *) * n); + for (i = 0; i < n; i++) + { + disposition[i] = (filterDisposition *)malloc(sizeof(filterDisposition)); + } + + // Allocation memory for values of score function for each block on the level + scores = (float *)malloc(sizeof(float) * (diff1 * diff2)); + + // A dot product vectors of feature map and weights of root filter +#ifdef FFT_CONV + getFFTImageFeatureMap(H->pyramid[level], &mapImage); + getFFTImageFilterObject(all_F[0], H->pyramid[level]->sizeX, H->pyramid[level]->sizeY, &rootFilterImage); + res = convFFTConv2d(mapImage, rootFilterImage, all_F[0]->sizeX, all_F[0]->sizeY, &f); + freeFFTImage(&mapImage); + freeFFTImage(&rootFilterImage); +#else + // Allocation memory for saving a dot product vectors of feature map and + // weights of root filter + f = (float *)malloc(sizeof(float) * (diff1 * diff2)); + // A dot product vectors of feature map and weights of root filter + res = convolution(all_F[0], H->pyramid[level], f); +#endif + if (res != LATENT_SVM_OK) + { + free(f); + free(scores); + for (i = 0; i < n; i++) + { + free(disposition[i]); + } + free(disposition); + return res; + } + + // Computation values of function D for each part filter + // on the level (level - LAMBDA) + partsLevel = level - LAMBDA; + // For feature map at the level 'partsLevel' add nullable border + map = featureMapBorderPartFilter(H->pyramid[partsLevel], + maxXBorder, maxYBorder); + + // Computation the maximum of score function + sumScorePartDisposition = 0.0; +#ifdef FFT_CONV + getFFTImageFeatureMap(map, &mapImage); + for (k = 1; k <= n; k++) + { + filterDispositionLevelFFT(all_F[k], mapImage, + &(disposition[k - 1]->score), + &(disposition[k - 1]->x), + &(disposition[k - 1]->y)); + } + freeFFTImage(&mapImage); +#else + for (k = 1; k <= n; k++) + { + filterDispositionLevel(all_F[k], map, + &(disposition[k - 1]->score), + &(disposition[k - 1]->x), + &(disposition[k - 1]->y)); + } +#endif + scores[0] = f[0] - sumScorePartDisposition + b; + maxScore = scores[0]; + (*kPoints) = 0; + for (i = 0; i < diff1; i++) + { + for (j = 0; j < diff2; j++) + { + sumScorePartDisposition = 0.0; + for (k = 1; k <= n; k++) + { + // This condition takes on a value true + // when filter goes beyond the boundaries of block set + if ((2 * i + all_F[k]->V.y < + map->sizeY - all_F[k]->sizeY + 1) && + (2 * j + all_F[k]->V.x < + map->sizeX - all_F[k]->sizeX + 1)) + { + index = (2 * i + all_F[k]->V.y) * + (map->sizeX - all_F[k]->sizeX + 1) + + (2 * j + all_F[k]->V.x); + sumScorePartDisposition += disposition[k - 1]->score[index]; + } + } + scores[i * diff2 + j] = f[i * diff2 + j] - sumScorePartDisposition + b; + if (maxScore < scores[i * diff2 + j]) + { + maxScore = scores[i * diff2 + j]; + (*kPoints) = 1; + } + else if ((scores[i * diff2 + j] - maxScore) * + (scores[i * diff2 + j] - maxScore) <= EPS) + { + (*kPoints)++; + } /* if (maxScore < scores[i * diff2 + j]) */ + } + } + + // Allocation memory for saving positions of root filter and part filters + (*points) = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + (*partsDisplacement) = (CvPoint **)malloc(sizeof(CvPoint *) * (*kPoints)); + for (i = 0; i < (*kPoints); i++) + { + (*partsDisplacement)[i] = (CvPoint *)malloc(sizeof(CvPoint) * n); + } + + /*// DEBUG + strcat(buf, tmp); + file = fopen(buf, "w+"); + //*/ + // Construction of the set of positions for root filter + // that correspond the maximum of score function on the level + (*score) = maxScore; + last = 0; + for (i = 0; i < diff1; i++) + { + for (j = 0; j < diff2; j++) + { + if ((scores[i * diff2 + j] - maxScore) * + (scores[i * diff2 + j] - maxScore) <= EPS) + { + (*points)[last].y = i; + (*points)[last].x = j; + for (k = 1; k <= n; k++) + { + if ((2 * i + all_F[k]->V.y < + map->sizeY - all_F[k]->sizeY + 1) && + (2 * j + all_F[k]->V.x < + map->sizeX - all_F[k]->sizeX + 1)) + { + index = (2 * i + all_F[k]->V.y) * + (map->sizeX - all_F[k]->sizeX + 1) + + (2 * j + all_F[k]->V.x); + (*partsDisplacement)[last][k - 1].x = + disposition[k - 1]->x[index]; + (*partsDisplacement)[last][k - 1].y = + disposition[k - 1]->y[index]; + } + } + last++; + } /* if ((scores[i * diff2 + j] - maxScore) * + (scores[i * diff2 + j] - maxScore) <= EPS) */ + //fprintf(file, "%lf;", scores[i * diff2 + j]); + } + //fprintf(file, "\n"); + } + //fclose(file); + //free(tmp); + + // Release allocated memory + for (i = 0; i < n ; i++) + { + free(disposition[i]->score); + free(disposition[i]->x); + free(disposition[i]->y); + free(disposition[i]); + } + free(disposition); + free(f); + free(scores); + freeFeatureMapObject(&map); + return LATENT_SVM_OK; +} + +/* +// Computation score function at the level that exceed threshold +// +// API +// int thresholdFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// level - feature pyramid level for computation maximum score +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// score - score function at the level that exceed threshold +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int thresholdFunctionalScoreFixedLevel(const filterObject **all_F, int n, + const featurePyramid *H, + int level, float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, CvPoint **points, int *kPoints, + CvPoint ***partsDisplacement) +{ + int i, j, k, dimX, dimY, nF0, mF0, p; + int diff1, diff2, index, last, partsLevel; + filterDisposition **disposition; + float *f; + float *scores; + float sumScorePartDisposition; + int res; + featureMap *map; +#ifdef FFT_CONV + fftImage *rootFilterImage, *mapImage; +#else +#endif + /* + // DEBUG variables + FILE *file; + char *tmp; + char buf[40] = "..\\Data\\score\\score", buf1[10] = ".csv"; + tmp = (char *)malloc(sizeof(char) * 80); + itoa(level, tmp, 10); + strcat(tmp, buf1); + //*/ + + // Feature map matrix dimension on the level + dimX = H->pyramid[level]->sizeX; + dimY = H->pyramid[level]->sizeY; + + // Number of features + p = H->pyramid[level]->p; + + // Getting dimension of root filter + nF0 = all_F[0]->sizeY; + mF0 = all_F[0]->sizeX; + // Processing the situation when root filter goes + // beyond the boundaries of the block set + if (nF0 > dimY || mF0 > dimX) + { + return LATENT_SVM_FAILED_SUPERPOSITION; + } + + diff1 = dimY - nF0 + 1; + diff2 = dimX - mF0 + 1; + + // Allocation memory for saving values of function D + // on the level for each part filter + disposition = (filterDisposition **)malloc(sizeof(filterDisposition *) * n); + for (i = 0; i < n; i++) + { + disposition[i] = (filterDisposition *)malloc(sizeof(filterDisposition)); + } + + // Allocation memory for values of score function for each block on the level + scores = (float *)malloc(sizeof(float) * (diff1 * diff2)); + // A dot product vectors of feature map and weights of root filter +#ifdef FFT_CONV + getFFTImageFeatureMap(H->pyramid[level], &mapImage); + getFFTImageFilterObject(all_F[0], H->pyramid[level]->sizeX, H->pyramid[level]->sizeY, &rootFilterImage); + res = convFFTConv2d(mapImage, rootFilterImage, all_F[0]->sizeX, all_F[0]->sizeY, &f); + freeFFTImage(&mapImage); + freeFFTImage(&rootFilterImage); +#else + // Allocation memory for saving a dot product vectors of feature map and + // weights of root filter + f = (float *)malloc(sizeof(float) * (diff1 * diff2)); + res = convolution(all_F[0], H->pyramid[level], f); +#endif + if (res != LATENT_SVM_OK) + { + free(f); + free(scores); + for (i = 0; i < n; i++) + { + free(disposition[i]); + } + free(disposition); + return res; + } + + // Computation values of function D for each part filter + // on the level (level - LAMBDA) + partsLevel = level - LAMBDA; + // For feature map at the level 'partsLevel' add nullable border + map = featureMapBorderPartFilter(H->pyramid[partsLevel], + maxXBorder, maxYBorder); + + // Computation the maximum of score function + sumScorePartDisposition = 0.0; +#ifdef FFT_CONV + getFFTImageFeatureMap(map, &mapImage); + for (k = 1; k <= n; k++) + { + filterDispositionLevelFFT(all_F[k], mapImage, + &(disposition[k - 1]->score), + &(disposition[k - 1]->x), + &(disposition[k - 1]->y)); + } + freeFFTImage(&mapImage); +#else + for (k = 1; k <= n; k++) + { + filterDispositionLevel(all_F[k], map, + &(disposition[k - 1]->score), + &(disposition[k - 1]->x), + &(disposition[k - 1]->y)); + } +#endif + (*kPoints) = 0; + for (i = 0; i < diff1; i++) + { + for (j = 0; j < diff2; j++) + { + sumScorePartDisposition = 0.0; + for (k = 1; k <= n; k++) + { + // This condition takes on a value true + // when filter goes beyond the boundaries of block set + if ((2 * i + all_F[k]->V.y < + map->sizeY - all_F[k]->sizeY + 1) && + (2 * j + all_F[k]->V.x < + map->sizeX - all_F[k]->sizeX + 1)) + { + index = (2 * i + all_F[k]->V.y) * + (map->sizeX - all_F[k]->sizeX + 1) + + (2 * j + all_F[k]->V.x); + sumScorePartDisposition += disposition[k - 1]->score[index]; + } + } + scores[i * diff2 + j] = f[i * diff2 + j] - sumScorePartDisposition + b; + if (scores[i * diff2 + j] > scoreThreshold) + { + (*kPoints)++; + } + } + } + + // Allocation memory for saving positions of root filter and part filters + (*points) = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + (*partsDisplacement) = (CvPoint **)malloc(sizeof(CvPoint *) * (*kPoints)); + for (i = 0; i < (*kPoints); i++) + { + (*partsDisplacement)[i] = (CvPoint *)malloc(sizeof(CvPoint) * n); + } + + /*// DEBUG + strcat(buf, tmp); + file = fopen(buf, "w+"); + //*/ + // Construction of the set of positions for root filter + // that correspond score function on the level that exceed threshold + (*score) = (float *)malloc(sizeof(float) * (*kPoints)); + last = 0; + for (i = 0; i < diff1; i++) + { + for (j = 0; j < diff2; j++) + { + if (scores[i * diff2 + j] > scoreThreshold) + { + (*score)[last] = scores[i * diff2 + j]; + (*points)[last].y = i; + (*points)[last].x = j; + for (k = 1; k <= n; k++) + { + if ((2 * i + all_F[k]->V.y < + map->sizeY - all_F[k]->sizeY + 1) && + (2 * j + all_F[k]->V.x < + map->sizeX - all_F[k]->sizeX + 1)) + { + index = (2 * i + all_F[k]->V.y) * + (map->sizeX - all_F[k]->sizeX + 1) + + (2 * j + all_F[k]->V.x); + (*partsDisplacement)[last][k - 1].x = + disposition[k - 1]->x[index]; + (*partsDisplacement)[last][k - 1].y = + disposition[k - 1]->y[index]; + } + } + last++; + } + //fprintf(file, "%lf;", scores[i * diff2 + j]); + } + //fprintf(file, "\n"); + } + //fclose(file); + //free(tmp); + + // Release allocated memory + for (i = 0; i < n ; i++) + { + free(disposition[i]->score); + free(disposition[i]->x); + free(disposition[i]->y); + free(disposition[i]); + } + free(disposition); + free(f); + free(scores); + freeFeatureMapObject(&map); + return LATENT_SVM_OK; +} + +/* +// Computation the maximum of the score function +// +// API +// int maxFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, float b, + int maxXBorder, int maxYBorder, + float *score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// OUTPUT +// score - the maximum of the score function +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int maxFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, float b, + int maxXBorder, int maxYBorder, + float *score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement) +{ + int l, i, j, k, s, f, level, numLevels; + float *tmpScore; + CvPoint ***tmpPoints; + CvPoint ****tmpPartsDisplacement; + int *tmpKPoints; + float maxScore; + int res; + + /* DEBUG + FILE *file; + //*/ + + // Computation the number of levels for seaching object, + // first lambda-levels are used for computation values + // of score function for each position of root filter + numLevels = H->countLevel - H->lambda; + + // Allocation memory for maximum value of score function for each level + tmpScore = (float *)malloc(sizeof(float) * numLevels); + // Allocation memory for the set of points that corresponds + // to the maximum of score function + tmpPoints = (CvPoint ***)malloc(sizeof(CvPoint **) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpPoints[i] = (CvPoint **)malloc(sizeof(CvPoint *)); + } + // Allocation memory for memory for saving parts displacement on each level + tmpPartsDisplacement = (CvPoint ****)malloc(sizeof(CvPoint ***) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpPartsDisplacement[i] = (CvPoint ***)malloc(sizeof(CvPoint **)); + } + // Number of points that corresponds to the maximum + // of score function on each level + tmpKPoints = (int *)malloc(sizeof(int) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpKPoints[i] = 0; + } + + // Set current value of the maximum of score function + res = maxFunctionalScoreFixedLevel(all_F, n, H, H->lambda, b, + maxXBorder, maxYBorder, + &(tmpScore[0]), + tmpPoints[0], + &(tmpKPoints[0]), + tmpPartsDisplacement[0]); + maxScore = tmpScore[0]; + (*kPoints) = tmpKPoints[0]; + + // Computation maxima of score function on each level + // and getting the maximum on all levels + /* DEBUG: maxScore + file = fopen("maxScore.csv", "w+"); + fprintf(file, "%i;%lf;\n", H->lambda, tmpScore[0]); + //*/ + for (l = H->lambda + 1; l < H->countLevel; l++) + { + k = l - H->lambda; + res = maxFunctionalScoreFixedLevel(all_F, n, H, l, b, + maxXBorder, maxYBorder, + &(tmpScore[k]), + tmpPoints[k], + &(tmpKPoints[k]), + tmpPartsDisplacement[k]); + //fprintf(file, "%i;%lf;\n", l, tmpScore[k]); + if (res != LATENT_SVM_OK) + { + continue; + } + if (maxScore < tmpScore[k]) + { + maxScore = tmpScore[k]; + (*kPoints) = tmpKPoints[k]; + } + else if ((maxScore - tmpScore[k]) * (maxScore - tmpScore[k]) <= EPS) + { + (*kPoints) += tmpKPoints[k]; + } /* if (maxScore < tmpScore[k]) else if (...)*/ + } + //fclose(file); + + // Allocation memory for levels + (*levels) = (int *)malloc(sizeof(int) * (*kPoints)); + // Allocation memory for the set of points + (*points) = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + // Allocation memory for parts displacement + (*partsDisplacement) = (CvPoint **)malloc(sizeof(CvPoint *) * (*kPoints)); + + // Filling the set of points, levels and parts displacement + s = 0; + f = 0; + for (i = 0; i < numLevels; i++) + { + if ((tmpScore[i] - maxScore) * (tmpScore[i] - maxScore) <= EPS) + { + // Computation the number of level + level = i + H->lambda; + + // Addition a set of points + f += tmpKPoints[i]; + for (j = s; j < f; j++) + { + (*levels)[j] = level; + (*points)[j] = (*tmpPoints[i])[j - s]; + (*partsDisplacement)[j] = (*(tmpPartsDisplacement[i]))[j - s]; + } + s = f; + } /* if ((tmpScore[i] - maxScore) * (tmpScore[i] - maxScore) <= EPS) */ + } + (*score) = maxScore; + + // Release allocated memory + for (i = 0; i < numLevels; i++) + { + free(tmpPoints[i]); + free(tmpPartsDisplacement[i]); + } + free(tmpPoints); + free(tmpScore); + free(tmpKPoints); + + return LATENT_SVM_OK; +} + +/* +// Computation score function that exceed threshold +// +// API +// int thresholdFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement); +// INPUT +// all_F - the set of filters (the first element is root filter, + the other - part filters) +// n - the number of part filters +// H - feature pyramid +// b - linear term of the score function +// maxXBorder - the largest root filter size (X-direction) +// maxYBorder - the largest root filter size (Y-direction) +// scoreThreshold - score threshold +// OUTPUT +// score - score function values that exceed threshold +// points - the set of root filter positions (in the block space) +// levels - the set of levels +// kPoints - number of root filter positions +// partsDisplacement - displacement of part filters (in the block space) +// RESULT +// Error status +*/ +int thresholdFunctionalScore(const filterObject **all_F, int n, + const featurePyramid *H, + float b, + int maxXBorder, int maxYBorder, + float scoreThreshold, + float **score, + CvPoint **points, int **levels, int *kPoints, + CvPoint ***partsDisplacement) +{ + int l, i, j, k, s, f, level, numLevels; + float **tmpScore; + CvPoint ***tmpPoints; + CvPoint ****tmpPartsDisplacement; + int *tmpKPoints; + int res; + + /* DEBUG + FILE *file; + //*/ + + // Computation the number of levels for seaching object, + // first lambda-levels are used for computation values + // of score function for each position of root filter + numLevels = H->countLevel - H->lambda; + + // Allocation memory for values of score function for each level + // that exceed threshold + tmpScore = (float **)malloc(sizeof(float*) * numLevels); + // Allocation memory for the set of points that corresponds + // to the maximum of score function + tmpPoints = (CvPoint ***)malloc(sizeof(CvPoint **) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpPoints[i] = (CvPoint **)malloc(sizeof(CvPoint *)); + } + // Allocation memory for memory for saving parts displacement on each level + tmpPartsDisplacement = (CvPoint ****)malloc(sizeof(CvPoint ***) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpPartsDisplacement[i] = (CvPoint ***)malloc(sizeof(CvPoint **)); + } + // Number of points that corresponds to the maximum + // of score function on each level + tmpKPoints = (int *)malloc(sizeof(int) * numLevels); + for (i = 0; i < numLevels; i++) + { + tmpKPoints[i] = 0; + } + + // Computation maxima of score function on each level + // and getting the maximum on all levels + /* DEBUG: maxScore + file = fopen("maxScore.csv", "w+"); + fprintf(file, "%i;%lf;\n", H->lambda, tmpScore[0]); + //*/ + (*kPoints) = 0; + for (l = H->lambda; l < H->countLevel; l++) + { + k = l - H->lambda; + //printf("Score at the level %i\n", l); + res = thresholdFunctionalScoreFixedLevel(all_F, n, H, l, b, + maxXBorder, maxYBorder, scoreThreshold, + &(tmpScore[k]), + tmpPoints[k], + &(tmpKPoints[k]), + tmpPartsDisplacement[k]); + //fprintf(file, "%i;%lf;\n", l, tmpScore[k]); + if (res != LATENT_SVM_OK) + { + continue; + } + (*kPoints) += tmpKPoints[k]; + } + //fclose(file); + + // Allocation memory for levels + (*levels) = (int *)malloc(sizeof(int) * (*kPoints)); + // Allocation memory for the set of points + (*points) = (CvPoint *)malloc(sizeof(CvPoint) * (*kPoints)); + // Allocation memory for parts displacement + (*partsDisplacement) = (CvPoint **)malloc(sizeof(CvPoint *) * (*kPoints)); + // Allocation memory for score function values + (*score) = (float *)malloc(sizeof(float) * (*kPoints)); + + // Filling the set of points, levels and parts displacement + s = 0; + f = 0; + for (i = 0; i < numLevels; i++) + { + // Computation the number of level + level = i + H->lambda; + + // Addition a set of points + f += tmpKPoints[i]; + for (j = s; j < f; j++) + { + (*levels)[j] = level; + (*points)[j] = (*tmpPoints[i])[j - s]; + (*score)[j] = tmpScore[i][j - s]; + (*partsDisplacement)[j] = (*(tmpPartsDisplacement[i]))[j - s]; + } + s = f; + } + + // Release allocated memory + for (i = 0; i < numLevels; i++) + { + free(tmpPoints[i]); + free(tmpPartsDisplacement[i]); + } + free(tmpPoints); + free(tmpScore); + free(tmpKPoints); + free(tmpPartsDisplacement); + + return LATENT_SVM_OK; +} + +void sort(int n, const float* x, int* indices) +{ + int i, j; + for (i = 0; i < n; i++) + for (j = i + 1; j < n; j++) + { + if (x[indices[j]] > x[indices[i]]) + { + //float x_tmp = x[i]; + int index_tmp = indices[i]; + //x[i] = x[j]; + indices[i] = indices[j]; + //x[j] = x_tmp; + indices[j] = index_tmp; + } + } +} + +/* +// Perform non-maximum suppression algorithm (described in original paper) +// to remove "similar" bounding boxes +// +// API +// int nonMaximumSuppression(int numBoxes, const CvPoint *points, + const CvPoint *oppositePoints, const float *score, + float overlapThreshold, + int *numBoxesOut, CvPoint **pointsOut, + CvPoint **oppositePointsOut, float **scoreOut); +// INPUT +// numBoxes - number of bounding boxes +// points - array of left top corner coordinates +// oppositePoints - array of right bottom corner coordinates +// score - array of detection scores +// overlapThreshold - threshold: bounding box is removed if overlap part + is greater than passed value +// OUTPUT +// numBoxesOut - the number of bounding boxes algorithm returns +// pointsOut - array of left top corner coordinates +// oppositePointsOut - array of right bottom corner coordinates +// scoreOut - array of detection scores +// RESULT +// Error status +*/ +int nonMaximumSuppression(int numBoxes, const CvPoint *points, + const CvPoint *oppositePoints, const float *score, + float overlapThreshold, + int *numBoxesOut, CvPoint **pointsOut, + CvPoint **oppositePointsOut, float **scoreOut) +{ + int i, j, index; + float* box_area = (float*)malloc(numBoxes * sizeof(float)); + int* indices = (int*)malloc(numBoxes * sizeof(int)); + int* is_suppressed = (int*)malloc(numBoxes * sizeof(int)); + + for (i = 0; i < numBoxes; i++) + { + indices[i] = i; + is_suppressed[i] = 0; + box_area[i] = (float)( (oppositePoints[i].x - points[i].x + 1) * + (oppositePoints[i].y - points[i].y + 1)); + } + + sort(numBoxes, score, indices); + for (i = 0; i < numBoxes; i++) + { + if (!is_suppressed[indices[i]]) + { + for (j = i + 1; j < numBoxes; j++) + { + if (!is_suppressed[indices[j]]) + { + int x1max = max(points[indices[i]].x, points[indices[j]].x); + int x2min = min(oppositePoints[indices[i]].x, oppositePoints[indices[j]].x); + int y1max = max(points[indices[i]].y, points[indices[j]].y); + int y2min = min(oppositePoints[indices[i]].y, oppositePoints[indices[j]].y); + int overlapWidth = x2min - x1max + 1; + int overlapHeight = y2min - y1max + 1; + if (overlapWidth > 0 && overlapHeight > 0) + { + float overlapPart = (overlapWidth * overlapHeight) / box_area[indices[j]]; + if (overlapPart > overlapThreshold) + { + is_suppressed[indices[j]] = 1; + } + } + } + } + } + } + + *numBoxesOut = 0; + for (i = 0; i < numBoxes; i++) + { + if (!is_suppressed[i]) (*numBoxesOut)++; + } + + *pointsOut = (CvPoint *)malloc((*numBoxesOut) * sizeof(CvPoint)); + *oppositePointsOut = (CvPoint *)malloc((*numBoxesOut) * sizeof(CvPoint)); + *scoreOut = (float *)malloc((*numBoxesOut) * sizeof(float)); + index = 0; + for (i = 0; i < numBoxes; i++) + { + if (!is_suppressed[indices[i]]) + { + (*pointsOut)[index].x = points[indices[i]].x; + (*pointsOut)[index].y = points[indices[i]].y; + (*oppositePointsOut)[index].x = oppositePoints[indices[i]].x; + (*oppositePointsOut)[index].y = oppositePoints[indices[i]].y; + (*scoreOut)[index] = score[indices[i]]; + index++; + } + + } + + free(indices); + free(box_area); + free(is_suppressed); + + return LATENT_SVM_OK; +} \ No newline at end of file diff --git a/modules/objdetect/src/precomp.hpp b/modules/objdetect/src/precomp.hpp index e4c912beaf..c0ac7c1161 100644 --- a/modules/objdetect/src/precomp.hpp +++ b/modules/objdetect/src/precomp.hpp @@ -54,6 +54,8 @@ #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/core/core_c.h" +#include "opencv2/highgui/highgui_c.h" #include "opencv2/core/internal.hpp" #endif diff --git a/modules/objdetect/src/resizeimg.cpp b/modules/objdetect/src/resizeimg.cpp new file mode 100644 index 0000000000..404509b17a --- /dev/null +++ b/modules/objdetect/src/resizeimg.cpp @@ -0,0 +1,244 @@ +#include "_resizeimg.h" +#include +#include +#include + + + +IplImage * resize_opencv (IplImage * img, float scale){ + IplImage * imgTmp; + + int W, H, tW, tH; + + W = img->width; + H = img->height; + + tW = (int)(((float)W) * scale + 0.5); + tH = (int)(((float)H) * scale + 0.5); + + imgTmp = cvCreateImage(cvSize(tW , tH), img->depth, img->nChannels); + cvResize( + img, + imgTmp, + CV_INTER_AREA + ); + + return imgTmp; +} + +// +///* +// * Fast image subsampling. +// * This is used to construct the feature pyramid. +// */ +// +//// struct used for caching interpolation values +//typedef struct { +// int si, di; +// float alpha; +//}alphainfo; +// +//// copy src into dst using pre-computed interpolation values +//void alphacopy(float *src, float *dst, alphainfo *ofs, int n) { +// int i; +// for(i = 0; i < n; i++){ +// dst[ofs[i].di] += ofs[i].alpha * src[ofs[i].si]; +// } +//} +// +//int round(float val){ +// return (int)(val + 0.5); +//} +//void bzero(float * arr, int cnt){ +// int i; +// for(i = 0; i < cnt; i++){ +// arr[i] = 0.0f; +// } +//} +//// resize along each column +//// result is transposed, so we can apply it twice for a complete resize +//void resize1dtran(float *src, int sheight, float *dst, int dheight, +// int width, int chan) { +// alphainfo *ofs; +// float scale = (float)dheight/(float)sheight; +// float invscale = (float)sheight/(float)dheight; +// +// // we cache the interpolation values since they can be +// // shared among different columns +// int len = (int)ceilf(dheight*invscale) + 2*dheight; +// int k = 0; +// int dy; +// float fsy1; +// float fsy2; +// int sy1; +// int sy2; +// int sy; +// int c, x; +// float *s, *d; +// +// ofs = (alphainfo *) malloc (sizeof(alphainfo) * len); +// for (dy = 0; dy < dheight; dy++) { +// fsy1 = dy * invscale; +// fsy2 = fsy1 + invscale; +// sy1 = (int)ceilf(fsy1); +// sy2 = (int)floorf(fsy2); +// +// if (sy1 - fsy1 > 1e-3) { +// assert(k < len); +// assert(sy1 - 1 >= 0); +// ofs[k].di = dy*width; +// ofs[k].si = sy1-1; +// ofs[k++].alpha = (sy1 - fsy1) * scale; +// } +// +// for (sy = sy1; sy < sy2; sy++) { +// assert(k < len); +// assert(sy < sheight); +// ofs[k].di = dy*width; +// ofs[k].si = sy; +// ofs[k++].alpha = scale; +// } +// +// if (fsy2 - sy2 > 1e-3) { +// assert(k < len); +// assert(sy2 < sheight); +// ofs[k].di = dy*width; +// ofs[k].si = sy2; +// ofs[k++].alpha = (fsy2 - sy2) * scale; +// } +// } +// +// // resize each column of each color channel +// bzero(dst, chan*width*dheight); +// for (c = 0; c < chan; c++) { +// for (x = 0; x < width; x++) { +// s = src + c*width*sheight + x*sheight; +// d = dst + c*width*dheight + x; +// alphacopy(s, d, ofs, k); +// } +// } +// free(ofs); +//} +// +//IplImage * resize_article_dp(IplImage * img, float scale, const int k){ +// IplImage * imgTmp; +// float W, H; +// unsigned char *dataSrc; +// float * dataf; +// float *src, *dst, *tmp; +// int i, j, kk, channels; +// int index; +// int widthStep; +// int tW, tH; +// +// W = (float)img->width; +// H = (float)img->height; +// channels = img->nChannels; +// widthStep = img->widthStep; +// +// tW = (int)(((float)W) * scale + 0.5f); +// tH = (int)(((float)H) * scale + 0.5f); +// +// src = (float *)malloc(sizeof(float) * (int)(W * H * 3)); +// +// dataSrc = (unsigned char*)(img->imageData); +// index = 0; +// for (kk = 0; kk < channels; kk++) +// { +// for (i = 0; i < W; i++) +// { +// for (j = 0; j < H; j++) +// { +// src[index++] = (float)dataSrc[j * widthStep + i * channels + kk]; +// } +// } +// } +// +// imgTmp = cvCreateImage(cvSize(tW , tH), IPL_DEPTH_32F, channels); +// +// dst = (float *)malloc(sizeof(float) * (int)(tH * tW) * channels); +// tmp = (float *)malloc(sizeof(float) * (int)(tH * W) * channels); +// +// resize1dtran(src, (int)H, tmp, (int)tH, (int)W , 3); +// +// resize1dtran(tmp, (int)W, dst, (int)tW, (int)tH, 3); +// +// index = 0; +// //dataf = (float*)imgTmp->imageData; +// for (kk = 0; kk < channels; kk++) +// { +// for (i = 0; i < tW; i++) +// { +// for (j = 0; j < tH; j++) +// { +// dataf = (float*)(imgTmp->imageData + j * imgTmp->widthStep); +// dataf[ i * channels + kk] = dst[index++]; +// } +// } +// } +// +// free(src); +// free(dst); +// free(tmp); +// return imgTmp; +//} +// +//IplImage * resize_article_dp1(IplImage * img, float scale, const int k){ +// IplImage * imgTmp; +// float W, H; +// float * dataf; +// float *src, *dst, *tmp; +// int i, j, kk, channels; +// int index; +// int widthStep; +// int tW, tH; +// +// W = (float)img->width; +// H = (float)img->height; +// channels = img->nChannels; +// widthStep = img->widthStep; +// +// tW = (int)(((float)W) * scale + 0.5f); +// tH = (int)(((float)H) * scale + 0.5f); +// +// src = (float *)malloc(sizeof(float) * (int)(W * H) * 3); +// +// index = 0; +// for (kk = 0; kk < channels; kk++) +// { +// for (i = 0; i < W; i++) +// { +// for (j = 0; j < H; j++) +// { +// src[index++] = (float)(*( (float *)(img->imageData + j * widthStep) + i * channels + kk)); +// } +// } +// } +// +// imgTmp = cvCreateImage(cvSize(tW , tH), IPL_DEPTH_32F, channels); +// +// dst = (float *)malloc(sizeof(float) * (int)(tH * tW) * channels); +// tmp = (float *)malloc(sizeof(float) * (int)(tH * W) * channels); +// +// resize1dtran(src, (int)H, tmp, (int)tH, (int)W , 3); +// +// resize1dtran(tmp, (int)W, dst, (int)tW, (int)tH, 3); +// +// index = 0; +// for (kk = 0; kk < channels; kk++) +// { +// for (i = 0; i < tW; i++) +// { +// for (j = 0; j < tH; j++) +// { +// dataf = (float *)(imgTmp->imageData + j * imgTmp->widthStep); +// dataf[ i * channels + kk] = dst[index++]; +// } +// } +// } +// +// free(src); +// free(dst); +// free(tmp); +// return imgTmp; +//} \ No newline at end of file diff --git a/modules/objdetect/src/routine.cpp b/modules/objdetect/src/routine.cpp new file mode 100644 index 0000000000..b55e9f185b --- /dev/null +++ b/modules/objdetect/src/routine.cpp @@ -0,0 +1,103 @@ +#include "_routine.h" + +int allocFilterObject(filterObject **obj, const int sizeX, const int sizeY, const int p, const int xp){ + int i; + (*obj) = (filterObject *)malloc(sizeof(filterObject)); + (*obj)->sizeX = sizeX; + (*obj)->sizeY = sizeY; + (*obj)->p = p ; + (*obj)->xp = xp ; + (*obj)->fineFunction[0] = 0.0f; + (*obj)->fineFunction[1] = 0.0f; + (*obj)->fineFunction[2] = 0.0f; + (*obj)->fineFunction[3] = 0.0f; + (*obj)->V.x = 0; + (*obj)->V.y = 0; + (*obj)->V.l = 0; + (*obj)->H = (float *) malloc(sizeof (float) * (sizeX * sizeY * p)); + for(i = 0; i < sizeX * sizeY * p; i++){ + (*obj)->H[i] = 0.0f; + } + return LATENT_SVM_OK; +} +int freeFilterObject (filterObject **obj){ + if(*obj == NULL) return 0; + free((*obj)->H); + free(*obj); + (*obj) = NULL; + return LATENT_SVM_OK; +} + +int allocFeatureMapObject(featureMap **obj, const int sizeX, const int sizeY, const int p, const int xp){ + int i; + (*obj) = (featureMap *)malloc(sizeof(featureMap)); + (*obj)->sizeX = sizeX; + (*obj)->sizeY = sizeY; + (*obj)->p = p ; + (*obj)->xp = xp ; + (*obj)->Map = (float *) malloc(sizeof (float) * (sizeX * sizeY * p)); + for(i = 0; i < sizeX * sizeY * p; i++){ + (*obj)->Map[i] = 0.0; + } + return LATENT_SVM_OK; +} +int freeFeatureMapObject (featureMap **obj){ + if(*obj == NULL) return 0; + free((*obj)->Map); + free(*obj); + (*obj) = NULL; + return LATENT_SVM_OK; +} + +int allocFeaturePyramidObject(featurePyramid **obj, const int lambda, const int countLevel){ + (*obj) = (featurePyramid *)malloc(sizeof(featurePyramid)); + (*obj)->countLevel = countLevel; + (*obj)->pyramid = (featureMap **)malloc(sizeof(featureMap *) * countLevel); + (*obj)->lambda = lambda; + return LATENT_SVM_OK; +} + +int freeFeaturePyramidObject (featurePyramid **obj){ + int i; + if(*obj == NULL) return 0; + for(i = 0; i < (*obj)->countLevel; i++) + freeFeatureMapObject(&((*obj)->pyramid[i])); + free((*obj)->pyramid); + free(*obj); + (*obj) = NULL; + return LATENT_SVM_OK; +} + +int allocFFTImage(fftImage **image, int p, int dimX, int dimY) +{ + int i, j, size; + *image = (fftImage *)malloc(sizeof(fftImage)); + (*image)->p = p; + (*image)->dimX = dimX; + (*image)->dimY = dimY; + (*image)->channels = (float **)malloc(sizeof(float *) * p); + size = 2 * dimX * dimY; + for (i = 0; i < p; i++) + { + (*image)->channels[i] = (float *)malloc(sizeof(float) * size); + for (j = 0; j < size; j++) + { + (*image)->channels[i][j] = 0.0; + } + } + return LATENT_SVM_OK; +} + +int freeFFTImage(fftImage **image) +{ + unsigned int i; + if (*image == NULL) return LATENT_SVM_OK; + for (i = 0; i < (*image)->p; i++) + { + free((*image)->channels[i]); + (*image)->channels[i] = NULL; + } + free((*image)->channels); + (*image)->channels = NULL; + return LATENT_SVM_OK; +} \ No newline at end of file diff --git a/samples/c/000028.jpg b/samples/c/000028.jpg new file mode 100644 index 0000000000..df4a907e5f Binary files /dev/null and b/samples/c/000028.jpg differ diff --git a/samples/c/cat.xml b/samples/c/cat.xml new file mode 100644 index 0000000000..85fcf09088 Binary files /dev/null and b/samples/c/cat.xml differ diff --git a/samples/c/latentsvmdetect.cpp b/samples/c/latentsvmdetect.cpp new file mode 100644 index 0000000000..76c9840452 --- /dev/null +++ b/samples/c/latentsvmdetect.cpp @@ -0,0 +1,49 @@ +#include "opencv2/objdetect/objdetect.hpp" +#include "opencv2/core/core_c.h" +#include "opencv2/highgui/highgui_c.h" +#include + +using namespace cv; + +const char* model_filename = "cat.xml"; +const char* image_filename = "000028.jpg"; + +void detect_and_draw_objects( IplImage* image, CvLatentSvmDetector* detector) +{ + CvMemStorage* storage = cvCreateMemStorage(0); + CvSeq* detections = 0; + int i = 0; + int64 start = 0, finish = 0; + + start = cvGetTickCount(); + detections = cvLatentSvmDetectObjects(image, detector, storage); + finish = cvGetTickCount(); + printf("detection time = %.3f\n", (float)(finish - start) / (float)(cvGetTickFrequency() * 1000000.0)); + + for( i = 0; i < detections->total; i++ ) + { + CvObjectDetection detection = *(CvObjectDetection*)cvGetSeqElem( detections, i ); + CvRect bounding_box = detection.rect; + cvRectangle( image, cvPoint(bounding_box.x, bounding_box.y), + cvPoint(bounding_box.x + bounding_box.width, + bounding_box.y + bounding_box.height), + CV_RGB(255,0,0), 3 ); + } + cvReleaseMemStorage( &storage ); +} + + +int main(int argc, char* argv[]) +{ + IplImage* image = cvLoadImage(image_filename); + CvLatentSvmDetector* detector = cvLoadLatentSvmDetector(model_filename); + detect_and_draw_objects( image, detector ); + cvNamedWindow( "test", 0 ); + cvShowImage( "test", image ); + cvWaitKey(0); + cvReleaseLatentSvmDetector( &detector ); + cvReleaseImage( &image ); + cvDestroyAllWindows(); + + return 0; +} \ No newline at end of file