mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
397 lines
12 KiB
397 lines
12 KiB
#include "precomp.hpp" |
|
#include "_lsvm_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; |
|
}
|
|
|