nbis: re-add step to remove perimeter points
This step helps to drop false minutiae for short sensors and
it was accidentally dropped during NBIS update. Re-add this step
and add a patch to update script to ensure that it's not dropped
during next update.
Fixes: 9fb789dc78
("nbis: Update to NBIS 5.0.0")
This commit is contained in:
parent
8626c64831
commit
297236b51a
5 changed files with 405 additions and 1 deletions
|
@ -260,6 +260,8 @@ typedef struct g_lfsparms{
|
||||||
int pores_steps_bwd;
|
int pores_steps_bwd;
|
||||||
double pores_min_dist2;
|
double pores_min_dist2;
|
||||||
double pores_max_ratio;
|
double pores_max_ratio;
|
||||||
|
int remove_perimeter_pts;
|
||||||
|
int min_pp_distance;
|
||||||
|
|
||||||
/* Ridge Counting Controls */
|
/* Ridge Counting Controls */
|
||||||
int max_nbrs;
|
int max_nbrs;
|
||||||
|
@ -609,6 +611,9 @@ typedef struct g_lfsparms{
|
||||||
/* contour points to be considered a pore. */
|
/* contour points to be considered a pore. */
|
||||||
#define PORES_MAX_RATIO 2.25
|
#define PORES_MAX_RATIO 2.25
|
||||||
|
|
||||||
|
/* Points which are closer than this distance to scan perimeter will be removed */
|
||||||
|
#define PERIMETER_PTS_DISTANCE 10
|
||||||
|
|
||||||
|
|
||||||
/***** RIDGE COUNTING CONSTANTS *****/
|
/***** RIDGE COUNTING CONSTANTS *****/
|
||||||
|
|
||||||
|
@ -1123,6 +1128,9 @@ extern int remove_or_adjust_side_minutiae(MINUTIAE *, unsigned char *,
|
||||||
extern int remove_or_adjust_side_minutiae_V2(MINUTIAE *,
|
extern int remove_or_adjust_side_minutiae_V2(MINUTIAE *,
|
||||||
unsigned char *, const int, const int,
|
unsigned char *, const int, const int,
|
||||||
int *, const int, const int, const LFSPARMS *);
|
int *, const int, const int, const LFSPARMS *);
|
||||||
|
extern int remove_perimeter_pts(MINUTIAE *minutiae,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms);
|
||||||
|
|
||||||
/* results.c */
|
/* results.c */
|
||||||
extern int write_text_results(char *, const int, const int, const int,
|
extern int write_text_results(char *, const int, const int, const int,
|
||||||
|
|
|
@ -150,6 +150,8 @@ LFSPARMS g_lfsparms = {
|
||||||
PORES_STEPS_BWD,
|
PORES_STEPS_BWD,
|
||||||
PORES_MIN_DIST2,
|
PORES_MIN_DIST2,
|
||||||
PORES_MAX_RATIO,
|
PORES_MAX_RATIO,
|
||||||
|
FALSE, /* not removing perimeter points by default */
|
||||||
|
PERIMETER_PTS_DISTANCE,
|
||||||
|
|
||||||
/* Ridge Counting Controls */
|
/* Ridge Counting Controls */
|
||||||
MAX_NBRS,
|
MAX_NBRS,
|
||||||
|
@ -234,6 +236,8 @@ LFSPARMS g_lfsparms_V2 = {
|
||||||
PORES_STEPS_BWD,
|
PORES_STEPS_BWD,
|
||||||
PORES_MIN_DIST2,
|
PORES_MIN_DIST2,
|
||||||
PORES_MAX_RATIO,
|
PORES_MAX_RATIO,
|
||||||
|
FALSE, /* not removing perimeter points by default */
|
||||||
|
PERIMETER_PTS_DISTANCE,
|
||||||
|
|
||||||
/* Ridge Counting Controls */
|
/* Ridge Counting Controls */
|
||||||
MAX_NBRS,
|
MAX_NBRS,
|
||||||
|
|
|
@ -195,6 +195,11 @@ int remove_false_minutia_V2(MINUTIAE *minutiae,
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 11. Remove minutiae on image edge */
|
||||||
|
if((ret = remove_perimeter_pts(minutiae, bdata, iw, ih, lfsparms))) {
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,6 +1334,159 @@ int remove_pointing_invblock_V2(MINUTIAE *minutiae,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mark_minutiae_in_range(MINUTIAE *minutiae, int *to_remove, int x, int y,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int i, dist;
|
||||||
|
for (i = 0; i < minutiae->num; i++) {
|
||||||
|
if (to_remove[i])
|
||||||
|
continue;
|
||||||
|
dist = (int)sqrt((x - minutiae->list[i]->x) * (x - minutiae->list[i]->x) +
|
||||||
|
(y - minutiae->list[i]->y) * (y - minutiae->list[i]->y));
|
||||||
|
if (dist < lfsparms->min_pp_distance) {
|
||||||
|
to_remove[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: remove_perimeter_pts - Takes a list of true and false minutiae and
|
||||||
|
#cat: attempts to detect and remove those false minutiae that
|
||||||
|
#cat: belong to image edge
|
||||||
|
|
||||||
|
Input:
|
||||||
|
minutiae - list of true and false minutiae
|
||||||
|
bdata - binary image data (0==while & 1==black)
|
||||||
|
iw - width (in pixels) of image
|
||||||
|
ih - height (in pixels) of image
|
||||||
|
lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
Output:
|
||||||
|
minutiae - list of pruned minutiae
|
||||||
|
Return Code:
|
||||||
|
Zero - successful completion
|
||||||
|
Negative - system error
|
||||||
|
**************************************************************************/
|
||||||
|
int remove_perimeter_pts(MINUTIAE *minutiae,
|
||||||
|
unsigned char *bdata, const int iw, const int ih,
|
||||||
|
const LFSPARMS *lfsparms)
|
||||||
|
{
|
||||||
|
int i, j, ret, *to_remove;
|
||||||
|
int *left, *left_up, *left_down;
|
||||||
|
int *right, *right_up, *right_down;
|
||||||
|
int removed = 0;
|
||||||
|
int left_min, right_max;
|
||||||
|
|
||||||
|
if (!lfsparms->remove_perimeter_pts)
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
to_remove = calloc(minutiae->num, sizeof(int));
|
||||||
|
left = calloc(ih, sizeof(int));
|
||||||
|
left_up = calloc(ih, sizeof(int));
|
||||||
|
left_down = calloc(ih, sizeof(int));
|
||||||
|
right = calloc(ih, sizeof(int));
|
||||||
|
right_up = calloc(ih, sizeof(int));
|
||||||
|
right_down = calloc(ih, sizeof(int));
|
||||||
|
|
||||||
|
/* Pass downwards */
|
||||||
|
left_min = iw - 1;
|
||||||
|
right_max = 0;
|
||||||
|
for (i = 0; i < ih; i++) {
|
||||||
|
for (j = 0; j < left_min; j++) {
|
||||||
|
if ((bdata[i * iw + j] != 0)) {
|
||||||
|
left_min = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (left_min == (iw - 1))
|
||||||
|
left_down[i] = -1;
|
||||||
|
else
|
||||||
|
left_down[i] = left_min;
|
||||||
|
for (j = iw - 1; j >= right_max; j--) {
|
||||||
|
if ((bdata[i * iw + j] != 0)) {
|
||||||
|
right_max = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right_max == 0)
|
||||||
|
right_down[i] = -1;
|
||||||
|
else
|
||||||
|
right_down[i] = right_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pass upwards */
|
||||||
|
left_min = iw - 1;
|
||||||
|
right_max = 0;
|
||||||
|
for (i = ih - 1; i >= 0; i--) {
|
||||||
|
for (j = 0; j < left_min; j++) {
|
||||||
|
if ((bdata[i * iw + j] != 0)) {
|
||||||
|
left_min = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (left_min == (iw - 1))
|
||||||
|
left_up[i] = -1;
|
||||||
|
else
|
||||||
|
left_up[i] = left_min;
|
||||||
|
for (j = iw - 1; j >= right_max; j--) {
|
||||||
|
if ((bdata[i * iw + j] != 0)) {
|
||||||
|
right_max = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right_max == 0)
|
||||||
|
right_up[i] = -1;
|
||||||
|
else
|
||||||
|
right_up[i] = right_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merge */
|
||||||
|
left_min = left_down[ih - 1];
|
||||||
|
right_max = right_down[ih - 1];
|
||||||
|
for (i = 0; i < ih; i++) {
|
||||||
|
if (left_down[i] != left_min)
|
||||||
|
left[i] = left_down[i];
|
||||||
|
else
|
||||||
|
left[i] = left_up[i];
|
||||||
|
|
||||||
|
if (right_down[i] != right_max)
|
||||||
|
right[i] = right_down[i];
|
||||||
|
else
|
||||||
|
right[i] = right_up[i];
|
||||||
|
}
|
||||||
|
free(left_up);
|
||||||
|
free(left_down);
|
||||||
|
free(right_up);
|
||||||
|
free(right_down);
|
||||||
|
|
||||||
|
/* Mark minitiae close to the edge */
|
||||||
|
for (i = 0; i < ih; i++) {
|
||||||
|
if (left[i] != -1)
|
||||||
|
mark_minutiae_in_range(minutiae, to_remove, left[i], i, lfsparms);
|
||||||
|
if (right[i] != -1)
|
||||||
|
mark_minutiae_in_range(minutiae, to_remove, right[i], i, lfsparms);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(left);
|
||||||
|
free(right);
|
||||||
|
|
||||||
|
for (i = minutiae->num - 1; i >= 0; i--) {
|
||||||
|
/* If the current minutia index is flagged for removal ... */
|
||||||
|
if (to_remove[i]){
|
||||||
|
removed ++;
|
||||||
|
/* Remove the minutia from the minutiae list. */
|
||||||
|
if((ret = remove_minutia(i, minutiae))){
|
||||||
|
free(to_remove);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(to_remove);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
#cat: remove_overlaps - Takes a list of true and false minutiae and
|
#cat: remove_overlaps - Takes a list of true and false minutiae and
|
||||||
|
|
231
libfprint/nbis/remove-perimeter-pts.patch
Normal file
231
libfprint/nbis/remove-perimeter-pts.patch
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
diff --git nbis/include/lfs.h nbis/include/lfs.h
|
||||||
|
index f4f38d7..8b12e73 100644
|
||||||
|
--- nbis/include/lfs.h
|
||||||
|
+++ nbis/include/lfs.h
|
||||||
|
@@ -260,6 +260,8 @@ typedef struct g_lfsparms{
|
||||||
|
int pores_steps_bwd;
|
||||||
|
double pores_min_dist2;
|
||||||
|
double pores_max_ratio;
|
||||||
|
+ int remove_perimeter_pts;
|
||||||
|
+ int min_pp_distance;
|
||||||
|
|
||||||
|
/* Ridge Counting Controls */
|
||||||
|
int max_nbrs;
|
||||||
|
@@ -609,6 +611,9 @@ typedef struct g_lfsparms{
|
||||||
|
/* contour points to be considered a pore. */
|
||||||
|
#define PORES_MAX_RATIO 2.25
|
||||||
|
|
||||||
|
+/* Points which are closer than this distance to scan perimeter will be removed */
|
||||||
|
+#define PERIMETER_PTS_DISTANCE 10
|
||||||
|
+
|
||||||
|
|
||||||
|
/***** RIDGE COUNTING CONSTANTS *****/
|
||||||
|
|
||||||
|
@@ -1123,6 +1128,9 @@ extern int remove_or_adjust_side_minutiae(MINUTIAE *, unsigned char *,
|
||||||
|
extern int remove_or_adjust_side_minutiae_V2(MINUTIAE *,
|
||||||
|
unsigned char *, const int, const int,
|
||||||
|
int *, const int, const int, const LFSPARMS *);
|
||||||
|
+extern int remove_perimeter_pts(MINUTIAE *minutiae,
|
||||||
|
+ unsigned char *bdata, const int iw, const int ih,
|
||||||
|
+ const LFSPARMS *lfsparms);
|
||||||
|
|
||||||
|
/* results.c */
|
||||||
|
extern int write_text_results(char *, const int, const int, const int,
|
||||||
|
diff --git nbis/mindtct/globals.c nbis/mindtct/globals.c
|
||||||
|
index da10c15..79bc583 100644
|
||||||
|
--- nbis/mindtct/globals.c
|
||||||
|
+++ nbis/mindtct/globals.c
|
||||||
|
@@ -150,6 +150,8 @@ LFSPARMS g_lfsparms = {
|
||||||
|
PORES_STEPS_BWD,
|
||||||
|
PORES_MIN_DIST2,
|
||||||
|
PORES_MAX_RATIO,
|
||||||
|
+ FALSE, /* not removing perimeter points by default */
|
||||||
|
+ PERIMETER_PTS_DISTANCE,
|
||||||
|
|
||||||
|
/* Ridge Counting Controls */
|
||||||
|
MAX_NBRS,
|
||||||
|
@@ -234,6 +236,8 @@ LFSPARMS g_lfsparms_V2 = {
|
||||||
|
PORES_STEPS_BWD,
|
||||||
|
PORES_MIN_DIST2,
|
||||||
|
PORES_MAX_RATIO,
|
||||||
|
+ FALSE, /* not removing perimeter points by default */
|
||||||
|
+ PERIMETER_PTS_DISTANCE,
|
||||||
|
|
||||||
|
/* Ridge Counting Controls */
|
||||||
|
MAX_NBRS,
|
||||||
|
diff --git nbis/mindtct/remove.c nbis/mindtct/remove.c
|
||||||
|
index af5ab7d..7311f1c 100644
|
||||||
|
--- nbis/mindtct/remove.c
|
||||||
|
+++ nbis/mindtct/remove.c
|
||||||
|
@@ -195,6 +195,11 @@ int remove_false_minutia_V2(MINUTIAE *minutiae,
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* 11. Remove minutiae on image edge */
|
||||||
|
+ if((ret = remove_perimeter_pts(minutiae, bdata, iw, ih, lfsparms))) {
|
||||||
|
+ return (ret);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1329,6 +1334,159 @@ int remove_pointing_invblock_V2(MINUTIAE *minutiae,
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void mark_minutiae_in_range(MINUTIAE *minutiae, int *to_remove, int x, int y,
|
||||||
|
+ const LFSPARMS *lfsparms)
|
||||||
|
+{
|
||||||
|
+ int i, dist;
|
||||||
|
+ for (i = 0; i < minutiae->num; i++) {
|
||||||
|
+ if (to_remove[i])
|
||||||
|
+ continue;
|
||||||
|
+ dist = (int)sqrt((x - minutiae->list[i]->x) * (x - minutiae->list[i]->x) +
|
||||||
|
+ (y - minutiae->list[i]->y) * (y - minutiae->list[i]->y));
|
||||||
|
+ if (dist < lfsparms->min_pp_distance) {
|
||||||
|
+ to_remove[i] = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*************************************************************************
|
||||||
|
+**************************************************************************
|
||||||
|
+#cat: remove_perimeter_pts - Takes a list of true and false minutiae and
|
||||||
|
+#cat: attempts to detect and remove those false minutiae that
|
||||||
|
+#cat: belong to image edge
|
||||||
|
+
|
||||||
|
+ Input:
|
||||||
|
+ minutiae - list of true and false minutiae
|
||||||
|
+ bdata - binary image data (0==while & 1==black)
|
||||||
|
+ iw - width (in pixels) of image
|
||||||
|
+ ih - height (in pixels) of image
|
||||||
|
+ lfsparms - parameters and thresholds for controlling LFS
|
||||||
|
+ Output:
|
||||||
|
+ minutiae - list of pruned minutiae
|
||||||
|
+ Return Code:
|
||||||
|
+ Zero - successful completion
|
||||||
|
+ Negative - system error
|
||||||
|
+**************************************************************************/
|
||||||
|
+int remove_perimeter_pts(MINUTIAE *minutiae,
|
||||||
|
+ unsigned char *bdata, const int iw, const int ih,
|
||||||
|
+ const LFSPARMS *lfsparms)
|
||||||
|
+{
|
||||||
|
+ int i, j, ret, *to_remove;
|
||||||
|
+ int *left, *left_up, *left_down;
|
||||||
|
+ int *right, *right_up, *right_down;
|
||||||
|
+ int removed = 0;
|
||||||
|
+ int left_min, right_max;
|
||||||
|
+
|
||||||
|
+ if (!lfsparms->remove_perimeter_pts)
|
||||||
|
+ return(0);
|
||||||
|
+
|
||||||
|
+ to_remove = calloc(minutiae->num, sizeof(int));
|
||||||
|
+ left = calloc(ih, sizeof(int));
|
||||||
|
+ left_up = calloc(ih, sizeof(int));
|
||||||
|
+ left_down = calloc(ih, sizeof(int));
|
||||||
|
+ right = calloc(ih, sizeof(int));
|
||||||
|
+ right_up = calloc(ih, sizeof(int));
|
||||||
|
+ right_down = calloc(ih, sizeof(int));
|
||||||
|
+
|
||||||
|
+ /* Pass downwards */
|
||||||
|
+ left_min = iw - 1;
|
||||||
|
+ right_max = 0;
|
||||||
|
+ for (i = 0; i < ih; i++) {
|
||||||
|
+ for (j = 0; j < left_min; j++) {
|
||||||
|
+ if ((bdata[i * iw + j] != 0)) {
|
||||||
|
+ left_min = j;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (left_min == (iw - 1))
|
||||||
|
+ left_down[i] = -1;
|
||||||
|
+ else
|
||||||
|
+ left_down[i] = left_min;
|
||||||
|
+ for (j = iw - 1; j >= right_max; j--) {
|
||||||
|
+ if ((bdata[i * iw + j] != 0)) {
|
||||||
|
+ right_max = j;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (right_max == 0)
|
||||||
|
+ right_down[i] = -1;
|
||||||
|
+ else
|
||||||
|
+ right_down[i] = right_max;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Pass upwards */
|
||||||
|
+ left_min = iw - 1;
|
||||||
|
+ right_max = 0;
|
||||||
|
+ for (i = ih - 1; i >= 0; i--) {
|
||||||
|
+ for (j = 0; j < left_min; j++) {
|
||||||
|
+ if ((bdata[i * iw + j] != 0)) {
|
||||||
|
+ left_min = j;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (left_min == (iw - 1))
|
||||||
|
+ left_up[i] = -1;
|
||||||
|
+ else
|
||||||
|
+ left_up[i] = left_min;
|
||||||
|
+ for (j = iw - 1; j >= right_max; j--) {
|
||||||
|
+ if ((bdata[i * iw + j] != 0)) {
|
||||||
|
+ right_max = j;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (right_max == 0)
|
||||||
|
+ right_up[i] = -1;
|
||||||
|
+ else
|
||||||
|
+ right_up[i] = right_max;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Merge */
|
||||||
|
+ left_min = left_down[ih - 1];
|
||||||
|
+ right_max = right_down[ih - 1];
|
||||||
|
+ for (i = 0; i < ih; i++) {
|
||||||
|
+ if (left_down[i] != left_min)
|
||||||
|
+ left[i] = left_down[i];
|
||||||
|
+ else
|
||||||
|
+ left[i] = left_up[i];
|
||||||
|
+
|
||||||
|
+ if (right_down[i] != right_max)
|
||||||
|
+ right[i] = right_down[i];
|
||||||
|
+ else
|
||||||
|
+ right[i] = right_up[i];
|
||||||
|
+ }
|
||||||
|
+ free(left_up);
|
||||||
|
+ free(left_down);
|
||||||
|
+ free(right_up);
|
||||||
|
+ free(right_down);
|
||||||
|
+
|
||||||
|
+ /* Mark minitiae close to the edge */
|
||||||
|
+ for (i = 0; i < ih; i++) {
|
||||||
|
+ if (left[i] != -1)
|
||||||
|
+ mark_minutiae_in_range(minutiae, to_remove, left[i], i, lfsparms);
|
||||||
|
+ if (right[i] != -1)
|
||||||
|
+ mark_minutiae_in_range(minutiae, to_remove, right[i], i, lfsparms);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ free(left);
|
||||||
|
+ free(right);
|
||||||
|
+
|
||||||
|
+ for (i = minutiae->num - 1; i >= 0; i--) {
|
||||||
|
+ /* If the current minutia index is flagged for removal ... */
|
||||||
|
+ if (to_remove[i]){
|
||||||
|
+ removed ++;
|
||||||
|
+ /* Remove the minutia from the minutiae list. */
|
||||||
|
+ if((ret = remove_minutia(i, minutiae))){
|
||||||
|
+ free(to_remove);
|
||||||
|
+ return(ret);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ free(to_remove);
|
||||||
|
+
|
||||||
|
+ return (0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
#cat: remove_overlaps - Takes a list of true and false minutiae and
|
|
@ -194,4 +194,7 @@ spatch --sp-file remove-global-y.cocci bozorth3/* include/bozorth.h --in-place
|
||||||
patch -p0 < glib-mem-warning.patch
|
patch -p0 < glib-mem-warning.patch
|
||||||
|
|
||||||
# Also fix some scan-build warnings, mostly by adding assertions
|
# Also fix some scan-build warnings, mostly by adding assertions
|
||||||
patch -p0 < fix-scan-build-reports.patch
|
patch -p0 < fix-scan-build-reports.patch
|
||||||
|
|
||||||
|
# Add pass to remove perimeter points
|
||||||
|
patch -p0 < remove-perimeter-pts.patch
|
||||||
|
|
Loading…
Reference in a new issue