2
/***************************************************************************/
4
/***************************************************************************/
6
CRS.C - Center for Remote Sensing rectification routines
8
Written By: Brian J. Buckley
10
At: The Center for Remote Sensing
11
Michigan State University
13
East Lansing, MI 48824
18
Last Update: 12/26/91 Brian J. Buckley
19
Last Update: 1/24/92 Brian J. Buckley
20
Added printout of trnfile. Triggered by BDEBUG.
21
Last Update: 1/27/92 Brian J. Buckley
22
Fixed bug so that only the active control points were used.
25
/***************************************************************************/
27
/***************************************************************************/
34
#include <grass/gis.h>
52
typedef double DOUBLE;
56
#include <grass/imagery.h>
58
typedef double DOUBLE;
64
/* STRUCTURE FOR USE INTERNALLY WITH THESE FUNCTIONS. THESE FUNCTIONS EXPECT
65
SQUARE MATRICES SO ONLY ONE VARIABLE IS GIVEN (N) FOR THE MATRIX SIZE */
69
int n; /* SIZE OF THIS MATRIX (N x N) */
73
/* CALCULATE OFFSET INTO ARRAY BASED ON R/C */
75
#define M(row,col) m->v[(((row)-1)*(m->n))+(col)-1]
77
/***************************************************************************/
81
/***************************************************************************/
83
#define MSUCCESS 1 /* SUCCESS */
84
#define MNPTERR 0 /* NOT ENOUGH POINTS */
85
#define MUNSOLVABLE -1 /* NOT SOLVABLE */
86
#define MMEMERR -2 /* NOT ENOUGH MEMORY */
87
#define MPARMERR -3 /* PARAMETER ERROR */
88
#define MINTERR -4 /* INTERNAL ERROR */
90
/***************************************************************************/
92
FUNCTION PROTOTYPES FOR STATIC (INTERNAL) FUNCTIONS
95
/***************************************************************************/
99
static int calccoef(struct Control_Points *, double *, double *, int);
100
static int calcls(struct Control_Points *, struct MATRIX *,
101
DOUBLE *, DOUBLE *, double *, double *);
102
static int exactdet(struct Control_Points *, struct MATRIX *,
103
DOUBLE *, DOUBLE *, double *, double *);
104
static int solvemat(struct MATRIX *, DOUBLE *, DOUBLE *, double *, double *);
105
static DOUBLE term(int, double, double);
108
static int checkgeoref(struct Control_Points *, double *, double *, int, int,
114
static int calccoef();
116
static int exactdet();
117
static int solvemat();
118
static DOUBLE term();
121
static int checkgeoref();
126
/***************************************************************************/
128
USE THIS TRANSFORMATION FUNCTION IF YOU WANT TO DO ARRAYS.
131
/***************************************************************************/
135
extern void CRS_georef(int, DOUBLE *, DOUBLE *, DOUBLE *, DOUBLE *, int);
137
void CRS_georef2(int order, /* ORDER OF TRANSFORMATION TO BE PERFORMED, MUST MATCH THE
138
ORDER USED TO CALCULATE THE COEFFICIENTS */
139
double E[], /* EASTING COEFFICIENTS */
140
double N[], /* NORTHING COEFFICIENTS */
141
double e[], /* EASTINGS TO BE TRANSFORMED */
142
double n[], /* NORTHINGS TO BE TRANSFORMED */
143
int numpts /* NUMBER OF POINTS TO BE TRANSFORMED */
146
DOUBLE e3, e2n, e2, en2, en, e1, n3, n2, n1;
152
for (i = 0; i < numpts; i++) {
164
E[1] * e1 + E[2] * n1 +
165
E[3] * e2 + E[4] * en + E[5] * n2 +
166
E[6] * e3 + E[7] * e2n + E[8] * en2 + E[9] * n3;
168
N[1] * e1 + N[2] * n1 +
169
N[3] * e2 + N[4] * en + N[5] * n2 +
170
N[6] * e3 + N[7] * e2n + N[8] * en2 + N[9] * n3;
176
for (i = 0; i < numpts; i++) {
183
e[i] = E[0] + E[1] * e1 + E[2] * n1 +
184
E[3] * e2 + E[4] * en + E[5] * n2;
185
n[i] = N[0] + N[1] * e1 + N[2] * n1 +
186
N[3] * e2 + N[4] * en + N[5] * n2;
192
for (i = 0; i < numpts; i++) {
195
e[i] = E[0] + E[1] * e1 + E[2] * n1;
196
n[i] = N[0] + N[1] * e1 + N[2] * n1;
204
/***************************************************************************/
206
TRANSFORM A SINGLE COORDINATE PAIR.
209
/***************************************************************************/
211
int CRS_georef(double e1, /* EASTINGS TO BE TRANSFORMED */
212
double n1, /* NORTHINGS TO BE TRANSFORMED */
213
double *e, /* EASTINGS TO BE TRANSFORMED */
214
double *n, /* NORTHINGS TO BE TRANSFORMED */
215
double E[], /* EASTING COEFFICIENTS */
216
double N[], /* NORTHING COEFFICIENTS */
217
int order /* ORDER OF TRANSFORMATION TO BE PERFORMED, MUST MATCH THE
218
ORDER USED TO CALCULATE THE COEFFICIENTS */
221
DOUBLE e3, e2n, en2, n3, e2, en, n2;
226
*e = E[0] + E[1] * e1 + E[2] * n1;
227
*n = N[0] + N[1] * e1 + N[2] * n1;
236
*e = E[0] + E[1] * e1 + E[2] * n1 + E[3] * e2 + E[4] * en + E[5] * n2;
237
*n = N[0] + N[1] * e1 + N[2] * n1 + N[3] * e2 + N[4] * en + N[5] * n2;
251
E[1] * e1 + E[2] * n1 +
252
E[3] * e2 + E[4] * en + E[5] * n2 +
253
E[6] * e3 + E[7] * e2n + E[8] * en2 + E[9] * n3;
255
N[1] * e1 + N[2] * n1 +
256
N[3] * e2 + N[4] * en + N[5] * n2 +
257
N[6] * e3 + N[7] * e2n + N[8] * en2 + N[9] * n3;
269
/***************************************************************************/
271
COMPUTE THE GEOREFFERENCING COEFFICIENTS BASED ON A SET OF CONTROL POINTS
274
/***************************************************************************/
277
CRS_compute_georef_equations(struct Control_Points *cp, double E12[],
278
double N12[], double E21[], double N21[],
284
if (order < 1 || order > MAXORDER)
288
fp = fopen("error.dat", "w");
293
/* CALCULATE THE FORWARD TRANSFORMATION COEFFICIENTS */
295
status = calccoef(cp, E12, N12, order);
296
if (status != MSUCCESS)
300
checkgeoref(cp, E12, N12, order, 1, fp);
303
/* SWITCH THE 1 AND 2 EASTING AND NORTHING ARRAYS */
312
/* CALCULATE THE BACKWARD TRANSFORMATION COEFFICIENTS */
314
status = calccoef(cp, E21, N21, order);
317
checkgeoref(cp, E21, N21, order, 0, fp);
321
/* SWITCH THE 1 AND 2 EASTING AND NORTHING ARRAYS BACK */
333
/***************************************************************************/
335
COMPUTE THE GEOREFFERENCING COEFFICIENTS BASED ON A SET OF CONTROL POINTS
338
/***************************************************************************/
341
calccoef(struct Control_Points *cp, double E[], double N[], int order)
346
int numactive; /* NUMBER OF ACTIVE CONTROL POINTS */
349
/* CALCULATE THE NUMBER OF VALID CONTROL POINTS */
351
for (i = numactive = 0; i < cp->count; i++) {
352
if (cp->status[i] > 0)
356
/* CALCULATE THE MINIMUM NUMBER OF CONTROL POINTS NEEDED TO DETERMINE
357
A TRANSFORMATION OF THIS ORDER */
359
m.n = ((order + 1) * (order + 2)) / 2;
364
/* INITIALIZE MATRIX */
366
m.v = (DOUBLE *) G_calloc(m.n * m.n, sizeof(DOUBLE));
370
a = (DOUBLE *) G_calloc(m.n, sizeof(DOUBLE));
375
b = (DOUBLE *) G_calloc(m.n, sizeof(DOUBLE));
382
if (numactive == m.n)
383
status = exactdet(cp, &m, a, b, E, N);
385
status = calcls(cp, &m, a, b, E, N);
394
/***************************************************************************/
396
CALCULATE THE TRANSFORMATION COEFFICIENTS WITH EXACTLY THE MINIMUM
397
NUMBER OF CONTROL POINTS REQUIRED FOR THIS TRANSFORMATION.
400
/***************************************************************************/
402
static int exactdet(struct Control_Points *cp, struct MATRIX *m, DOUBLE a[], DOUBLE b[], double E[], /* EASTING COEFFICIENTS */
403
double N[] /* NORTHING COEFFICIENTS */
406
int pntnow, currow, j;
409
for (pntnow = 0; pntnow < cp->count; pntnow++) {
410
if (cp->status[pntnow] > 0) {
411
/* POPULATE MATRIX M */
414
fprintf(fp, "%2d ", pntnow + 1);
417
for (j = 1; j <= m->n; j++) {
418
M(currow, j) = term(j, cp->e1[pntnow], cp->n1[pntnow]);
420
fprintf(fp, "%+14.7le ", M(currow, j));
429
/* POPULATE MATRIX A AND B */
431
a[currow - 1] = cp->e2[pntnow];
432
b[currow - 1] = cp->n2[pntnow];
434
fprintf(fp, " %+14.7le ", a[currow - 1]);
435
fprintf(fp, "%+14.7le\n", b[currow - 1]);
442
fprintf(fp, "%2d UNUSED\n", pntnow + 1);
447
if (currow - 1 != m->n)
450
return (solvemat(m, a, b, E, N));
453
/***************************************************************************/
455
CALCULATE THE TRANSFORMATION COEFFICIENTS WITH MORE THAN THE MINIMUM
456
NUMBER OF CONTROL POINTS REQUIRED FOR THIS TRANSFORMATION. THIS
457
ROUTINE USES THE LEAST SQUARES METHOD TO COMPUTE THE COEFFICIENTS.
460
/***************************************************************************/
462
static int calcls(struct Control_Points *cp, struct MATRIX *m, DOUBLE a[], DOUBLE b[], double E[], /* EASTING COEFFICIENTS */
463
double N[] /* NORTHING COEFFICIENTS */
466
int i, j, n, numactive = 0;
468
/* INITIALIZE THE UPPER HALF OF THE MATRIX AND THE TWO COLUMN VECTORS */
470
for (i = 1; i <= m->n; i++) {
471
for (j = i; j <= m->n; j++)
473
a[i - 1] = b[i - 1] = 0.0;
476
/* SUM THE UPPER HALF OF THE MATRIX AND THE COLUMN VECTORS ACCORDING TO
477
THE LEAST SQUARES METHOD OF SOLVING OVER DETERMINED SYSTEMS */
479
for (n = 0; n < cp->count; n++) {
480
if (cp->status[n] > 0) {
482
for (i = 1; i <= m->n; i++) {
483
for (j = i; j <= m->n; j++)
485
term(i, cp->e1[n], cp->n1[n]) * term(j, cp->e1[n],
488
a[i - 1] += cp->e2[n] * term(i, cp->e1[n], cp->n1[n]);
489
b[i - 1] += cp->n2[n] * term(i, cp->e1[n], cp->n1[n]);
494
if (numactive <= m->n)
497
/* TRANSPOSE VALUES IN UPPER HALF OF M TO OTHER HALF */
499
for (i = 2; i <= m->n; i++) {
500
for (j = 1; j < i; j++)
504
return (solvemat(m, a, b, E, N));
507
/***************************************************************************/
509
CALCULATE THE X/Y TERM BASED ON THE TERM NUMBER
511
ORDER\TERM 1 2 3 4 5 6 7 8 9 10
513
2 e0n0 e1n0 e0n1 e2n0 e1n1 e0n2
514
3 e0n0 e1n0 e0n1 e2n0 e1n1 e0n2 e3n0 e2n1 e1n2 e0n3
517
/***************************************************************************/
519
static DOUBLE term(int term, double e, double n)
523
return ((DOUBLE) 1.0);
529
return ((DOUBLE) (e * e));
531
return ((DOUBLE) (e * n));
533
return ((DOUBLE) (n * n));
535
return ((DOUBLE) (e * e * e));
537
return ((DOUBLE) (e * e * n));
539
return ((DOUBLE) (e * n * n));
541
return ((DOUBLE) (n * n * n));
543
return ((DOUBLE) 0.0);
546
/***************************************************************************/
548
SOLVE FOR THE 'E' AND 'N' COEFFICIENTS BY USING A SOMEWHAT MODIFIED
549
GAUSSIAN ELIMINATION METHOD.
551
| M11 M12 ... M1n | | E0 | | a0 |
552
| M21 M22 ... M2n | | E1 | = | a1 |
553
| . . . . | | . | | . |
554
| Mn1 Mn2 ... Mnn | | En-1 | | an-1 |
558
| M11 M12 ... M1n | | N0 | | b0 |
559
| M21 M22 ... M2n | | N1 | = | b1 |
560
| . . . . | | . | | . |
561
| Mn1 Mn2 ... Mnn | | Nn-1 | | bn-1 |
564
/***************************************************************************/
566
static int solvemat(struct MATRIX *m,
567
DOUBLE a[], DOUBLE b[], double E[], double N[])
569
int i, j, i2, j2, imark;
571
DOUBLE pivot; /* ACTUAL VALUE OF THE LARGEST PIVOT CANDIDATE */
573
for (i = 1; i <= m->n; i++) {
576
/* find row with largest magnitude value for pivot value */
580
for (i2 = i + 1; i2 <= m->n; i2++) {
581
temp = fabs(M(i2, j));
582
if (temp > fabs(pivot)) {
588
/* if the pivot is very small then the points are nearly co-linear */
589
/* co-linear points result in an undefined matrix, and nearly */
590
/* co-linear points results in a solution with rounding error */
593
return (MUNSOLVABLE);
595
/* if row with highest pivot is not the current row, switch them */
598
for (j2 = 1; j2 <= m->n; j2++) {
600
M(imark, j2) = M(i, j2);
605
a[imark - 1] = a[i - 1];
609
b[imark - 1] = b[i - 1];
613
/* compute zeros above and below the pivot, and compute
614
values for the rest of the row as well */
616
for (i2 = 1; i2 <= m->n; i2++) {
618
factor = M(i2, j) / pivot;
619
for (j2 = j; j2 <= m->n; j2++)
620
M(i2, j2) -= factor * M(i, j2);
621
a[i2 - 1] -= factor * a[i - 1];
622
b[i2 - 1] -= factor * b[i - 1];
627
/* SINCE ALL OTHER VALUES IN THE MATRIX ARE ZERO NOW, CALCULATE THE
628
COEFFICIENTS BY DIVIDING THE COLUMN VECTORS BY THE DIAGONAL VALUES. */
630
for (i = 1; i <= m->n; i++) {
631
E[i - 1] = a[i - 1] / M(i, i);
632
N[i - 1] = b[i - 1] / M(i, i);
638
/***************************************************************************/
642
/***************************************************************************/
646
static int checkgeoref(struct Control_Points *cp,
647
double E[], double N[], int order, int forward,
650
DOUBLE xrms, yrms, dx, dy, dx2, dy2, totaldist, dist;
654
n = ((order + 1) * (order + 2)) / 2;
657
fprintf(fp, "FORWARD:\n");
659
fprintf(fp, "BACKWARD:\n");
661
fprintf(fp, "%d order\n", order);
662
for (i = 0; i < n; i++)
663
fprintf(fp, "%+.17E %+.17E\n", E[i], N[i]);
665
xrms = yrms = dx2 = dy2 = totaldist = 0.0;
667
for (i = 0; i < cp->count; i++) {
668
fprintf(fp, "\nCONTROL POINT: %d\n", i + 1);
670
fprintf(fp, "%20s: %+.20lE %+.20lE\n", "ORIGINAL POINT",
671
cp->e1[i], cp->n1[i]);
672
fprintf(fp, "%20s: %+.20lE %+.20lE\n", "DESIRED POINT",
673
cp->e2[i], cp->n2[i]);
675
if (cp->status[i] > 0) {
677
CRS_georef(cp->e1[i], cp->n1[i], &tempx, &tempy, E, N, order);
679
fprintf(fp, "%20s: %+.20lE %+.20lE\n", "CALCULATED POINT", tempx,
681
dx = tempx - cp->e2[i];
682
dy = tempy - cp->n2[i];
683
fprintf(fp, "%20s: %+.20lE %+.20lE\n", "RESIDUAL ERROR", dx, dy);
686
dist = sqrt(dx2 + dy2);
687
fprintf(fp, "%20s: %+.20lE\n", "DISTANCE (RMS) ERROR", dist);
695
fprintf(fp, "NOT USED\n");
697
xrms = sqrt(xrms / (DOUBLE) numactive);
698
yrms = sqrt(yrms / (DOUBLE) numactive);
700
fprintf(fp, "\n%20s: %+.20lE %+.20lE\n", "RMS ERROR", xrms, yrms);
702
fprintf(fp, "\n%20s: %+.20lE\n", "TOTAL RMS ERROR",
703
sqrt(xrms * xrms + yrms * yrms));
705
fprintf(fp, "\n%20s: %+.20lE\n", "AVG. DISTANCE ERROR",
706
totaldist / numactive);