|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
|
|
|
#include "include/lapjv.h" |
|
|
|
|
|
namespace PaddleDetection { |
|
|
|
|
|
|
|
|
|
|
|
int _ccrrt_dense(const int n, float *cost[], |
|
|
int *free_rows, int *x, int *y, float *v) |
|
|
{ |
|
|
int n_free_rows; |
|
|
bool *unique; |
|
|
|
|
|
for (int i = 0; i < n; i++) { |
|
|
x[i] = -1; |
|
|
v[i] = LARGE; |
|
|
y[i] = 0; |
|
|
} |
|
|
for (int i = 0; i < n; i++) { |
|
|
for (int j = 0; j < n; j++) { |
|
|
const float c = cost[i][j]; |
|
|
if (c < v[j]) { |
|
|
v[j] = c; |
|
|
y[j] = i; |
|
|
} |
|
|
} |
|
|
} |
|
|
NEW(unique, bool, n); |
|
|
memset(unique, TRUE, n); |
|
|
{ |
|
|
int j = n; |
|
|
do { |
|
|
j--; |
|
|
const int i = y[j]; |
|
|
if (x[i] < 0) { |
|
|
x[i] = j; |
|
|
} else { |
|
|
unique[i] = FALSE; |
|
|
y[j] = -1; |
|
|
} |
|
|
} while (j > 0); |
|
|
} |
|
|
n_free_rows = 0; |
|
|
for (int i = 0; i < n; i++) { |
|
|
if (x[i] < 0) { |
|
|
free_rows[n_free_rows++] = i; |
|
|
} else if (unique[i]) { |
|
|
const int j = x[i]; |
|
|
float min = LARGE; |
|
|
for (int j2 = 0; j2 < n; j2++) { |
|
|
if (j2 == (int)j) { |
|
|
continue; |
|
|
} |
|
|
const float c = cost[i][j2] - v[j2]; |
|
|
if (c < min) { |
|
|
min = c; |
|
|
} |
|
|
} |
|
|
v[j] -= min; |
|
|
} |
|
|
} |
|
|
FREE(unique); |
|
|
return n_free_rows; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _carr_dense( |
|
|
const int n, float *cost[], |
|
|
const int n_free_rows, |
|
|
int *free_rows, int *x, int *y, float *v) |
|
|
{ |
|
|
int current = 0; |
|
|
int new_free_rows = 0; |
|
|
int rr_cnt = 0; |
|
|
while (current < n_free_rows) { |
|
|
int i0; |
|
|
int j1, j2; |
|
|
float v1, v2, v1_new; |
|
|
bool v1_lowers; |
|
|
|
|
|
rr_cnt++; |
|
|
const int free_i = free_rows[current++]; |
|
|
j1 = 0; |
|
|
v1 = cost[free_i][0] - v[0]; |
|
|
j2 = -1; |
|
|
v2 = LARGE; |
|
|
for (int j = 1; j < n; j++) { |
|
|
const float c = cost[free_i][j] - v[j]; |
|
|
if (c < v2) { |
|
|
if (c >= v1) { |
|
|
v2 = c; |
|
|
j2 = j; |
|
|
} else { |
|
|
v2 = v1; |
|
|
v1 = c; |
|
|
j2 = j1; |
|
|
j1 = j; |
|
|
} |
|
|
} |
|
|
} |
|
|
i0 = y[j1]; |
|
|
v1_new = v[j1] - (v2 - v1); |
|
|
v1_lowers = v1_new < v[j1]; |
|
|
if (rr_cnt < current * n) { |
|
|
if (v1_lowers) { |
|
|
v[j1] = v1_new; |
|
|
} else if (i0 >= 0 && j2 >= 0) { |
|
|
j1 = j2; |
|
|
i0 = y[j2]; |
|
|
} |
|
|
if (i0 >= 0) { |
|
|
if (v1_lowers) { |
|
|
free_rows[--current] = i0; |
|
|
} else { |
|
|
free_rows[new_free_rows++] = i0; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
if (i0 >= 0) { |
|
|
free_rows[new_free_rows++] = i0; |
|
|
} |
|
|
} |
|
|
x[free_i] = j1; |
|
|
y[j1] = free_i; |
|
|
} |
|
|
return new_free_rows; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _find_dense(const int n, int lo, float *d, int *cols, int *y) |
|
|
{ |
|
|
int hi = lo + 1; |
|
|
float mind = d[cols[lo]]; |
|
|
for (int k = hi; k < n; k++) { |
|
|
int j = cols[k]; |
|
|
if (d[j] <= mind) { |
|
|
if (d[j] < mind) { |
|
|
hi = lo; |
|
|
mind = d[j]; |
|
|
} |
|
|
cols[k] = cols[hi]; |
|
|
cols[hi++] = j; |
|
|
} |
|
|
} |
|
|
return hi; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _scan_dense(const int n, float *cost[], |
|
|
int *plo, int*phi, |
|
|
float *d, int *cols, int *pred, |
|
|
int *y, float *v) |
|
|
{ |
|
|
int lo = *plo; |
|
|
int hi = *phi; |
|
|
float h, cred_ij; |
|
|
|
|
|
while (lo != hi) { |
|
|
int j = cols[lo++]; |
|
|
const int i = y[j]; |
|
|
const float mind = d[j]; |
|
|
h = cost[i][j] - v[j] - mind; |
|
|
|
|
|
for (int k = hi; k < n; k++) { |
|
|
j = cols[k]; |
|
|
cred_ij = cost[i][j] - v[j] - h; |
|
|
if (cred_ij < d[j]) { |
|
|
d[j] = cred_ij; |
|
|
pred[j] = i; |
|
|
if (cred_ij == mind) { |
|
|
if (y[j] < 0) { |
|
|
return j; |
|
|
} |
|
|
cols[k] = cols[hi]; |
|
|
cols[hi++] = j; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
*plo = lo; |
|
|
*phi = hi; |
|
|
return -1; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int find_path_dense( |
|
|
const int n, float *cost[], |
|
|
const int start_i, |
|
|
int *y, float *v, |
|
|
int *pred) |
|
|
{ |
|
|
int lo = 0, hi = 0; |
|
|
int final_j = -1; |
|
|
int n_ready = 0; |
|
|
int *cols; |
|
|
float *d; |
|
|
|
|
|
NEW(cols, int, n); |
|
|
NEW(d, float, n); |
|
|
|
|
|
for (int i = 0; i < n; i++) { |
|
|
cols[i] = i; |
|
|
pred[i] = start_i; |
|
|
d[i] = cost[start_i][i] - v[i]; |
|
|
} |
|
|
while (final_j == -1) { |
|
|
|
|
|
if (lo == hi) { |
|
|
n_ready = lo; |
|
|
hi = _find_dense(n, lo, d, cols, y); |
|
|
for (int k = lo; k < hi; k++) { |
|
|
const int j = cols[k]; |
|
|
if (y[j] < 0) { |
|
|
final_j = j; |
|
|
} |
|
|
} |
|
|
} |
|
|
if (final_j == -1) { |
|
|
final_j = _scan_dense( |
|
|
n, cost, &lo, &hi, d, cols, pred, y, v); |
|
|
} |
|
|
} |
|
|
|
|
|
{ |
|
|
const float mind = d[cols[lo]]; |
|
|
for (int k = 0; k < n_ready; k++) { |
|
|
const int j = cols[k]; |
|
|
v[j] += d[j] - mind; |
|
|
} |
|
|
} |
|
|
|
|
|
FREE(cols); |
|
|
FREE(d); |
|
|
|
|
|
return final_j; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _ca_dense( |
|
|
const int n, float *cost[], |
|
|
const int n_free_rows, |
|
|
int *free_rows, int *x, int *y, float *v) |
|
|
{ |
|
|
int *pred; |
|
|
|
|
|
NEW(pred, int, n); |
|
|
|
|
|
for (int *pfree_i = free_rows; pfree_i < free_rows + n_free_rows; pfree_i++) { |
|
|
int i = -1, j; |
|
|
int k = 0; |
|
|
|
|
|
j = find_path_dense(n, cost, *pfree_i, y, v, pred); |
|
|
while (i != *pfree_i) { |
|
|
i = pred[j]; |
|
|
y[j] = i; |
|
|
SWAP_INDICES(j, x[i]); |
|
|
k++; |
|
|
} |
|
|
} |
|
|
FREE(pred); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int lapjv_internal( |
|
|
const cv::Mat &cost, const bool extend_cost, const float cost_limit, |
|
|
int *x, int *y ) { |
|
|
int n_rows = cost.rows; |
|
|
int n_cols = cost.cols; |
|
|
int n; |
|
|
if (n_rows == n_cols) { |
|
|
n = n_rows; |
|
|
} else if (!extend_cost) { |
|
|
throw std::invalid_argument("Square cost array expected. If cost is intentionally non-square, pass extend_cost=True."); |
|
|
} |
|
|
|
|
|
|
|
|
if (extend_cost || cost_limit < LARGE) { |
|
|
n = n_rows + n_cols; |
|
|
} |
|
|
cv::Mat cost_expand(n, n, CV_32F); |
|
|
float expand_value; |
|
|
if (cost_limit < LARGE) { |
|
|
expand_value = cost_limit / 2; |
|
|
} else { |
|
|
double max_v; |
|
|
minMaxLoc(cost, nullptr, &max_v); |
|
|
expand_value = (float)max_v + 1; |
|
|
} |
|
|
|
|
|
for (int i = 0; i < n; ++i) { |
|
|
for (int j = 0; j < n; ++j) { |
|
|
cost_expand.at<float>(i, j) = expand_value; |
|
|
if (i >= n_rows && j >= n_cols) { |
|
|
cost_expand.at<float>(i, j) = 0; |
|
|
} else if (i < n_rows && j < n_cols) { |
|
|
cost_expand.at<float>(i, j) = cost.at<float>(i, j); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
float **cost_ptr; |
|
|
NEW(cost_ptr, float *, n); |
|
|
for (int i = 0; i < n; ++i) { |
|
|
NEW(cost_ptr[i], float, n); |
|
|
} |
|
|
for (int i = 0; i < n; ++i) { |
|
|
for (int j = 0; j < n; ++j) { |
|
|
cost_ptr[i][j] = cost_expand.at<float>(i, j); |
|
|
} |
|
|
} |
|
|
|
|
|
int ret; |
|
|
int *free_rows; |
|
|
float *v; |
|
|
int *x_c; |
|
|
int *y_c; |
|
|
|
|
|
NEW(free_rows, int, n); |
|
|
NEW(v, float, n); |
|
|
NEW(x_c, int, n); |
|
|
NEW(y_c, int, n); |
|
|
|
|
|
ret = _ccrrt_dense(n, cost_ptr, free_rows, x_c, y_c, v); |
|
|
int i = 0; |
|
|
while (ret > 0 && i < 2) { |
|
|
ret = _carr_dense(n, cost_ptr, ret, free_rows, x_c, y_c, v); |
|
|
i++; |
|
|
} |
|
|
if (ret > 0) { |
|
|
ret = _ca_dense(n, cost_ptr, ret, free_rows, x_c, y_c, v); |
|
|
} |
|
|
FREE(v); |
|
|
FREE(free_rows); |
|
|
for (int i = 0; i < n; ++i) { |
|
|
FREE(cost_ptr[i]); |
|
|
} |
|
|
FREE(cost_ptr); |
|
|
if (ret != 0) { |
|
|
if (ret == -1){ |
|
|
throw "Out of memory."; |
|
|
} |
|
|
throw "Unknown error (lapjv_internal)"; |
|
|
} |
|
|
|
|
|
for (int i = 0; i < n; ++i) { |
|
|
if (i < n_rows) { |
|
|
x[i] = x_c[i]; |
|
|
if (x[i] >= n_cols) { |
|
|
x[i] = -1; |
|
|
} |
|
|
} |
|
|
if (i < n_cols) { |
|
|
y[i] = y_c[i]; |
|
|
if (y[i] >= n_rows) { |
|
|
y[i] = -1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
FREE(x_c); |
|
|
FREE(y_c); |
|
|
return ret; |
|
|
} |
|
|
|
|
|
} |
|
|
|