mirror of
https://github.com/opencv/opencv.git
synced 2024-12-12 15:19:11 +08:00
29b13ec1de
This should allow many algorithms to take advantage of more parallelization technologies.
645 lines
22 KiB
C++
645 lines
22 KiB
C++
#include "precomp.hpp"
|
|
#include "_latentsvm.h"
|
|
#include "_lsvm_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
|
|
*/
|
|
CvLSVMFeaturePyramid* createFeaturePyramidWithBorder(IplImage *image,
|
|
int maxXBorder, int maxYBorder)
|
|
{
|
|
int opResult;
|
|
int bx, by;
|
|
int level;
|
|
CvLSVMFeaturePyramid *H;
|
|
|
|
// Obtaining feature pyramid
|
|
opResult = getFeaturePyramid(image, &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->numLevels; 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 CvLSVMFeaturePyramid *H, const CvLSVMFilterObject **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->numLevels, 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
|
|
*/
|
|
static 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 CvLSVMFeaturePyramid *H,
|
|
const CvLSVMFilterObject **all_F, int n,
|
|
float b,
|
|
int maxXBorder, int maxYBorder,
|
|
float scoreThreshold,
|
|
CvPoint **points, int **levels, int *kPoints,
|
|
float **score, CvPoint ***partsDisplacement,
|
|
int numThreads)
|
|
{
|
|
int opResult;
|
|
|
|
|
|
// Matching
|
|
#ifdef HAVE_TBB
|
|
if (numThreads <= 0)
|
|
{
|
|
opResult = LATENT_SVM_TBB_NUMTHREADS_NOT_CORRECT;
|
|
return opResult;
|
|
}
|
|
opResult = tbbThresholdFunctionalScore(all_F, n, H, b, maxXBorder, maxYBorder,
|
|
scoreThreshold, numThreads, score,
|
|
points, levels, kPoints,
|
|
partsDisplacement);
|
|
#else
|
|
opResult = thresholdFunctionalScore(all_F, n, H, b,
|
|
maxXBorder, maxYBorder,
|
|
scoreThreshold,
|
|
score, points, levels,
|
|
kPoints, partsDisplacement);
|
|
|
|
(void)numThreads;
|
|
#endif
|
|
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->numLevels, 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 CvLSVMFilterObject *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);
|
|
}
|
|
#ifdef HAVE_OPENCV_HIGHGUI
|
|
cvShowImage("Initial image", image);
|
|
#endif
|
|
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 CvLSVMFilterObject **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);
|
|
}
|
|
}
|
|
#ifdef HAVE_OPENCV_HIGHGUI
|
|
cvShowImage("Initial image", image);
|
|
#endif
|
|
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);
|
|
}
|
|
#ifdef HAVE_OPENCV_HIGHGUI
|
|
cvShowImage("Initial image", img);
|
|
#endif
|
|
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 CvLSVMFilterObject **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 ((unsigned)filters[componentIndex]->sizeX > *maxXBorder)
|
|
{
|
|
*maxXBorder = filters[componentIndex]->sizeX;
|
|
}
|
|
if ((unsigned)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 CvLSVMFeaturePyramid *H,
|
|
const CvLSVMFilterObject **filters,
|
|
int kComponents, const int *kPartFilters,
|
|
const float *b, float scoreThreshold,
|
|
CvPoint **points, CvPoint **oppPoints,
|
|
float **score, int *kPoints,
|
|
int numThreads)
|
|
{
|
|
//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++)
|
|
{
|
|
int error = searchObjectThreshold(H, &(filters[componentIndex]), kPartFilters[i],
|
|
b[i], maxXBorder, maxYBorder, scoreThreshold,
|
|
&(pointsArr[i]), &(levelsArr[i]), &(kPointsArr[i]),
|
|
&(scoreArr[i]), &(partsDisplacementArr[i]), numThreads);
|
|
if (error != LATENT_SVM_OK)
|
|
{
|
|
// Release allocated memory
|
|
free(pointsArr);
|
|
free(oppPointsArr);
|
|
free(scoreArr);
|
|
free(kPointsArr);
|
|
free(levelsArr);
|
|
free(partsDisplacementArr);
|
|
return LATENT_SVM_SEARCH_OBJECT_FAILED;
|
|
}
|
|
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;
|
|
}
|