-
Notifications
You must be signed in to change notification settings - Fork 168
/
main.cpp
492 lines (438 loc) · 17.8 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/** This is free and unencumbered software released into the public domain.
The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/
/* SPDX-License-Identifier: CC0-1.0 */
// $Id: hical.cpp 6715 2016-04-28 17:58:43Z tsucharski@GS.DOI.NET $
#include "Isis.h"
#include <cstdio>
#include <QString>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iostream>
#include "FileName.h"
#include "ProcessByLine.h"
#include "UserInterface.h"
#include "Pvl.h"
#include "PvlGroup.h"
#include "IString.h"
#include "HiCalConf.h"
#include "CollectorMap.h"
#include "HiCalTypes.h"
#include "HiCalUtil.h"
#include "HiCalData.h"
#include "Statistics.h"
#include "SplineFill.h" // SpineFillComp.h
#include "LowPassFilter.h" // LowPassFilterComp.h
#include "ZeroBufferSmooth.h" // DriftBuffer.h (Zf)
#include "ZeroBufferFit.h" // DriftCorrect.h (Zd)
#include "ZeroReverse.h" // OffsetCorrect.h (Zz)
#include "ZeroDark.h" // DarkSubtractComp.h (Zb)
#include "GainLineDrift.h" // GainVLineComp.h (Zg)
#include "GainNonLinearity.h" // Non-linear gain (new)
#include "GainChannelNormalize.h" // ZggModule.h (Zgg)
#include "GainFlatField.h" // FlatFieldComp.h (Za)
#include "GainTemperature.h" // TempGainCorrect.h (Zt)
#include "GainUnitConversion.h" // ZiofModule.h (Ziof)
using namespace Isis;
using namespace std;
//!< Define the matrix container for systematic processing
typedef CollectorMap<IString, HiVector, NoCaseStringCompare> MatrixList;
// Calibration parameter container
MatrixList *calVars = 0;
/**
* @brief Apply calibration to each HiRISE image line
*
* This function applies the calbration equation to each input image line. It
* gets matrices and constants from the \b calVars container that is established
* in the main with some user input via the configuration (CONF) parameter.
*
* @param in Input raw image line buffer
* @param out Output calibrated image line buffer
*/
void calibrate(Buffer &in, Buffer &out) {
const HiVector &ZBF = calVars->get("ZeroBufferFit");
const HiVector &ZRev = calVars->get("ZeroReverse");
const HiVector &ZD = calVars->get("ZeroDark");
const HiVector &GLD = calVars->get("GainLineDrift");
const HiVector &GCN = calVars->get("GainChannelNormalize");
const double GNL = calVars->get("GainNonLinearity")[0];
const HiVector &GFF = calVars->get("GainFlatField");
const HiVector > = calVars->get("GainTemperature");
const double GUC = calVars->get("GainUnitConversion")[0];
// Set current line (index)
int line(in.Line()-1);
if (calVars->exists("LastGoodLine")) {
int lastline = ((int) (calVars->get("LastGoodLine"))[0]) - 1;
if ( line > lastline ) { line = lastline; }
}
// Apply correction to point of non-linearity accumulating average
vector<double> data;
for (int i = 0 ; i < in.size() ; i++) {
if (IsSpecial(in[i])) {
out[i] = in[i];
}
else {
double hdn;
hdn = (in[i] - ZBF[line] - ZRev[i] - ZD[i]); // Drift, Reverse, Dark
hdn = hdn / GLD[line]; // GainLineDrift
data.push_back(hdn); // Accumulate average for non-linearity
out[i] = hdn;
}
}
// Second loop require to apply non-linearity gain correction from average
if ( data.size() > 0 ) { // No valid pixels means just that - done
// See HiCalUtil.h for the function that returns this stat.
double NLGain = 1.0 - (GNL * GainLineStat(data));
for (int i = 0 ; i < out.size() ; i++) {
if (!IsSpecial(out[i])) {
double hdn = out[i];
hdn = hdn * GCN[i] * NLGain * GFF[i] * GT[i]; // Gain, Non-linearity
// gain, FlatField,
// TempGain
out[i] = hdn / GUC; // I/F or DN or DN/US
}
}
}
return;
}
void IsisMain(){
const QString hical_program = "hical";
const QString hical_version = "5.0";
const QString hical_revision = "$Revision: 6715 $";
const QString hical_runtime = Application::DateTime();
UserInterface &ui = Application::GetUserInterface();
QString procStep("prepping phase");
try {
// The output from the last processing is the input into subsequent processing
ProcessByLine p;
Cube *hifrom = p.SetInputCube("FROM");
int nsamps = hifrom->sampleCount();
int nlines = hifrom->lineCount();
// Initialize the configuration file
QString conf(ui.GetAsString("CONF"));
HiCalConf hiconf(*(hifrom->label()), conf);
DbProfile hiprof = hiconf.getMatrixProfile();
// Check for label propagation and set the output cube
Cube *ocube = p.SetOutputCube("TO");
if ( !IsTrueValue(hiprof,"PropagateTables", "TRUE") ) {
RemoveHiBlobs(*(ocube->label()));
}
// Set specified profile if entered by user
if (ui.WasEntered("PROFILE")) {
hiconf.selectProfile(ui.GetAsString("PROFILE"));
}
// Add OPATH parameter to profiles
if (ui.WasEntered("OPATH")) {
hiconf.add("OPATH",ui.GetAsString("OPATH"));
}
else {
// Set default to output directory
hiconf.add("OPATH", FileName(ocube->fileName()).path());
}
// Do I/F output DN conversions
QString units = ui.GetString("UNITS");
// Allocate the calibration list
calVars = new MatrixList;
// Set up access to HiRISE ancillary data (tables, blobs) here. Note it they
// are gone, this will error out. See PropagateTables in conf file.
HiCalData caldata(*hifrom);
////////////////////////////////////////////////////////////////////////////
// Drift Correction (Zf) using buffer pixels
// Extracts specified regions of the calibration buffer pixels and runs
// series of lowpass filters. Apply spline fit if any missing data
// remains. Config file contains parameters for this operation.
procStep = "ZeroBufferSmooth module";
hiconf.selectProfile("ZeroBufferSmooth");
hiprof = hiconf.getMatrixProfile();
HiHistory ZbsHist;
ZbsHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
ZeroBufferSmooth zbs(caldata, hiconf);
calVars->add("ZeroBufferSmooth", zbs.ref());
ZbsHist = zbs.History();
if ( hiprof.exists("DumpModuleFile") ) {
zbs.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
// NOT RECOMMENDED! This is required for the next step!
// SURELY must be skipped with ZeroBufferSmooth step as well!
calVars->add("ZeroBufferSmooth", HiVector(nlines, 0.0));
ZbsHist.add("Debug::SkipModule invoked!");
}
/////////////////////////////////////////////////////////////////////
// ZeroBufferFit
// Compute second level of drift correction. The high level noise
// is removed from a modeled non-linear fit.
//
procStep = "ZeroBufferFit module";
HiHistory ZbfHist;
hiconf.selectProfile("ZeroBufferFit");
hiprof = hiconf.getMatrixProfile();
ZbfHist.add("Profile["+ hiprof.Name()+"]");
if (!SkipModule(hiprof) ) {
ZeroBufferFit zbf(hiconf);
calVars->add(hiconf.getProfileName(),
zbf.Normalize(zbf.Solve(calVars->get("ZeroBufferSmooth"))));
ZbfHist = zbf.History();
if ( hiprof.exists("DumpModuleFile") ) {
zbf.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nlines, 0.0));
ZbfHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// ZeroReverse
procStep = "ZeroReverse module";
hiconf.selectProfile("ZeroReverse");
hiprof = hiconf.getMatrixProfile();
HiHistory ZrHist;
ZrHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
ZeroReverse zr(caldata, hiconf);
calVars->add(hiconf.getProfileName(), zr.ref());
ZrHist = zr.History();
if ( hiprof.exists("DumpModuleFile") ) {
zr.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nsamps, 0.0));
ZrHist.add("Debug::SkipModule invoked!");
}
/////////////////////////////////////////////////////////////////
// ZeroDark removes dark current
//
procStep = "ZeroDark module";
hiconf.selectProfile("ZeroDark");
hiprof = hiconf.getMatrixProfile();
HiHistory ZdHist;
ZdHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
ZeroDark zd(hiconf);
calVars->add(hiconf.getProfileName(), zd.ref());
ZdHist = zd.History();
if ( hiprof.exists("DumpModuleFile") ) {
zd.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nsamps, 0.0));
ZdHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainLineDrift correct for gain-based drift
//
procStep = "GainLineDrift module";
hiconf.selectProfile("GainLineDrift");
hiprof = hiconf.getMatrixProfile();
HiHistory GldHist;
GldHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainLineDrift gld(hiconf);
calVars->add(hiconf.getProfileName(), gld.ref());
GldHist = gld.History();
if ( hiprof.exists("DumpModuleFile") ) {
gld.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nlines, 1.0));
GldHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainNonLinearity Correct for non-linear gain
procStep = "GainNonLinearity module";
hiconf.selectProfile("GainNonLinearity");
hiprof = hiconf.getMatrixProfile();
HiHistory GnlHist;
GnlHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainNonLinearity gnl(hiconf);
calVars->add(hiconf.getProfileName(), gnl.ref());
GnlHist = gnl.History();
if ( hiprof.exists("DumpModuleFile") ) {
gnl.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(1, 0.0));
GnlHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainChannelNormalize Correct for sample gain with the G matrix
procStep = "GainChannelNormalize module";
hiconf.selectProfile("GainChannelNormalize");
hiprof = hiconf.getMatrixProfile();
HiHistory GcnHist;
GcnHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainChannelNormalize gcn(hiconf);
calVars->add(hiconf.getProfileName(), gcn.ref());
GcnHist = gcn.History();
if ( hiprof.exists("DumpModuleFile") ) {
gcn.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nsamps, 1.0));
GcnHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainFlatField Flat field correction with A matrix
procStep = "GainFlatField module";
hiconf.selectProfile("GainFlatField");
hiprof = hiconf.getMatrixProfile();
HiHistory GffHist;
GffHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainFlatField gff(hiconf);
calVars->add(hiconf.getProfileName(), gff.ref());
GffHist = gff.History();
if ( hiprof.exists("DumpModuleFile") ) {
gff.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nsamps, 1.0));
GffHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainTemperature - Temperature-dependant gain correction
procStep = "GainTemperature module";
hiconf.selectProfile("GainTemperature");
hiprof = hiconf.getMatrixProfile();
HiHistory GtHist;
GtHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainTemperature gt(hiconf);
calVars->add(hiconf.getProfileName(), gt.ref());
GtHist = gt.History();
if ( hiprof.exists("DumpModuleFile") ) {
gt.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(nsamps, 1.0));
GtHist.add("Debug::SkipModule invoked!");
}
////////////////////////////////////////////////////////////////////
// GainUnitConversion converts to requested units
//
procStep = "GainUnitConversion module";
hiconf.selectProfile("GainUnitConversion");
hiprof = hiconf.getMatrixProfile();
HiHistory GucHist;
GucHist.add("Profile["+ hiprof.Name()+"]");
if ( !SkipModule(hiprof) ) {
GainUnitConversion guc(hiconf, units, hifrom);
calVars->add(hiconf.getProfileName(), guc.ref());
GucHist = guc.History();
if ( hiprof.exists("DumpModuleFile") ) {
guc.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof));
}
}
else {
calVars->add(hiconf.getProfileName(), HiVector(1,1.0));
GucHist.add("Debug::SkipModule invoked!");
GucHist.add("Units[Unknown]");
}
// Reset the profile selection to default
hiconf.selectProfile();
//----------------------------------------------------------------------
//
/////////////////////////////////////////////////////////////////////////
// Call the processing function
procStep = "calibration phase";
p.StartProcess(calibrate);
// Get the default profile for logging purposes
hiprof = hiconf.getMatrixProfile();
const QString conf_file = hiconf.filepath(conf);
// Quitely dumps parameter history to alternative format file. This
// is completely controlled by the configuration file
if ( hiprof.exists("DumpHistoryFile") ) {
procStep = "logging/reporting phase";
FileName hdump(hiconf.getMatrixSource("DumpHistoryFile",hiprof));
QString hdumpFile = hdump.expanded();
ofstream ofile(hdumpFile.toLatin1().data(), ios::out);
if (!ofile) {
QString mess = "Unable to open/create history dump file " +
hdump.expanded();
IException(IException::User, mess, _FILEINFO_).print();
}
else {
ofile << "Program: " << hical_program << endl;
ofile << "RunTime: " << hical_runtime << endl;
ofile << "Version: " << hical_version << endl;
ofile << "Revision: " << hical_revision << endl << endl;
ofile << "FROM: " << hifrom->fileName() << endl;
ofile << "TO: " << ocube->fileName() << endl;
ofile << "CONF: " << conf_file << endl << endl;
ofile << "/* " << hical_program << " application equation */\n"
<< "/* hdn = (idn - ZeroBufferFit(ZeroBufferSmooth) - ZeroReverse - ZeroDark) */\n"
<< "/* odn = hdn / GainLineDrift * GainNonLinearity * GainChannelNormalize */\n"
<< "/* * GainFlatField * GainTemperature / GainUnitConversion */\n\n";
ofile << "****** PARAMETER GENERATION HISTORY *******" << endl;
ofile << "\nZeroBufferSmooth = " << ZbsHist << endl;
ofile << "\nZeroBufferFit = " << ZbfHist << endl;
ofile << "\nZeroReverse = " << ZrHist << endl;
ofile << "\nZeroDark = " << ZdHist << endl;
ofile << "\nGainLineDrift = " << GldHist << endl;
ofile << "\nGainNonLinearity = " << GnlHist << endl;
ofile << "\nGainChannelNormalize = " << GcnHist << endl;
ofile << "\nGainFlatField = " << GffHist << endl;
ofile << "\nGainTemperature = " << GtHist << endl;
ofile << "\nGainUnitConversion = " << GucHist << endl;
ofile.close();
}
}
// Ensure the RadiometricCalibration group is out there
const QString rcalGroup("RadiometricCalibration");
if (!ocube->hasGroup(rcalGroup)) {
PvlGroup temp(rcalGroup);
ocube->putGroup(temp);
}
PvlGroup &rcal = ocube->group(rcalGroup);
rcal += PvlKeyword("Program", hical_program);
rcal += PvlKeyword("RunTime", hical_runtime);
rcal += PvlKeyword("Version",hical_version);
rcal += PvlKeyword("Revision",hical_revision);
PvlKeyword key("Conf", conf_file);
key.addCommentWrapped("/* " + hical_program + " application equation */");
key.addComment("/* hdn = idn - ZeroBufferFit(ZeroBufferSmooth) */");
key.addComment("/* - ZeroReverse - ZeroDark */");
key.addComment("/* odn = hdn / GainLineDrift * GainNonLinearity */");
key.addComment("/* * GainChannelNormalize * GainFlatField */");
key.addComment("/* * GainTemperature / GainUnitConversion */");
rcal += key;
// Record parameter generation history. Controllable in configuration
// file. Note this is optional because of a BUG!! in the ISIS label
// writer as this application was initially developed
if ( IsEqual(ConfKey(hiprof,"LogParameterHistory",QString("TRUE")),"TRUE")) {
rcal += ZbsHist.makekey("ZeroBufferSmooth");
rcal += ZbfHist.makekey("ZeroBufferFit");
rcal += ZrHist.makekey("ZeroReverse");
rcal += ZdHist.makekey("ZeroDark");
rcal += GldHist.makekey("GainLineDrift");
rcal += GnlHist.makekey("GainNonLinearity");
rcal += GcnHist.makekey("GainChannelNormalize");
rcal += GffHist.makekey("GainFlatField");
rcal += GtHist.makekey("GainTemperature");
rcal += GucHist.makekey("GainUnitConversion");
}
p.EndProcess();
}
catch (IException &ie) {
delete calVars;
calVars = 0;
QString mess = "Failed in " + procStep;
throw IException(ie, IException::User, mess.toLatin1().data(), _FILEINFO_);
}
// Clean up parameters
delete calVars;
calVars = 0;
}