USGS

Isis 3.0 Object Programmers' Reference

Home

HiEqualization.cpp
1 #include "HiEqualization.h"
2 
3 #include <iomanip>
4 
5 #include "Buffer.h"
6 #include "Cube.h"
7 #include "IException.h"
8 #include "LineManager.h"
9 #include "OverlapNormalization.h"
10 #include "OverlapStatistics.h"
11 #include "Process.h"
12 #include "ProcessByLine.h"
13 
14 using std::string;
15 using std::vector;
16 
17 
18 namespace Isis {
19 
20 
21  HiEqualization::HiEqualization(QString fromListName) :
22  Equalization() {
23  loadInputs(fromListName);
24  }
25 
26 
27  HiEqualization::~HiEqualization() {
28  }
29 
30 
31  void HiEqualization::calculateStatistics() {
32  // TODO member variable
33  const FileList &imageList = getInputs();
34  QString maxCubeStr = toString((int) imageList.size());
35 
36  // Adds statistics for whole and side regions of every cube
37  vector<Statistics *> statsList;
38  vector<Statistics *> leftStatsList;
39  vector<Statistics *> rightStatsList;
40  for (int img = 0; img < imageList.size(); img++) {
41  Statistics *stats = new Statistics();
42  Statistics *statsLeft = new Statistics();
43  Statistics *statsRight = new Statistics();
44 
45  QString cubeStr = toString((int) img + 1);
46 
47  ProcessByLine p;
48  p.Progress()->SetText("Calculating Statistics for Cube " +
49  cubeStr + " of " + maxCubeStr);
50  CubeAttributeInput att;
51  QString inp = imageList[img].toString();
52  p.SetInputCube(inp, att);
53  HiCalculateFunctor func(stats, statsLeft, statsRight, 100.0);
54  p.ProcessCubeInPlace(func, false);
55 
56  statsList.push_back(stats);
57  leftStatsList.push_back(statsLeft);
58  rightStatsList.push_back(statsRight);
59  }
60 
61  // Initialize the object that will calculate the gains and offsets
62  OverlapNormalization oNorm(statsList);
63 
64  // Add the known overlaps between two cubes, and apply a weight to each
65  // overlap equal the number of pixels in the overlapping area
66  for (int i = 0; i < imageList.size() - 1; i++) {
67  int j = i + 1;
68  oNorm.AddOverlap(*rightStatsList[i], i, *leftStatsList[j], j,
69  rightStatsList[i]->ValidPixels());
70  }
71 
72  loadHolds(&oNorm);
73 
74  // Attempt to solve the least squares equation
75  oNorm.Solve(OverlapNormalization::Both);
76 
77  clearAdjustments();
78  for (int img = 0; img < imageList.size(); img++) {
79  ImageAdjustment *adjustment = new ImageAdjustment(OverlapNormalization::Both);
80  adjustment->addGain(oNorm.Gain(img));
81  adjustment->addOffset(oNorm.Offset(img));
82  adjustment->addAverage(oNorm.Average(img));
83  addAdjustment(adjustment);
84  }
85 
86  addValid(imageList.size() - 1);
87  setResults();
88  }
89 
90 
91  void HiEqualization::fillOutList(FileList &outList, QString toListName) {
92  if (toListName.isEmpty()) {
93  generateOutputs(outList);
94  }
95  else {
96  FileList tempList;
97  loadOutputs(tempList, toListName);
98 
99  for (unsigned int i = 0; i < movedIndices.size(); i++) {
100  outList.push_back(tempList[movedIndices[i]]);
101  }
102  }
103  }
104 
105 
106  void HiEqualization::errorCheck(QString fromListName) {
107  const FileList &imageList = getInputs();
108 
109  // Ensures number of images is within bound
110  if (imageList.size() > 10) {
111  QString msg = "The input file [" + fromListName +
112  "] cannot contain more than 10 file names";
113  throw IException(IException::User, msg, _FILEINFO_);
114  }
115 
116  // Reference for converting a CPMM number to a CCD number
117  const int cpmm2ccd[] = {0, 1, 2, 3, 12, 4, 10, 11, 5, 13, 6, 7, 8, 9};
118 
119  // Place ccd in vector, try-catch opening cubes
120  vector<int> ccds;
121  for (int i = 0; i < imageList.size(); i++) {
122  try {
123  Cube cube1;
124  cube1.open(imageList[i].toString());
125  PvlGroup &from1Instrument = cube1.group("INSTRUMENT");
126  int cpmmNumber = from1Instrument["CpmmNumber"];
127  ccds.push_back(cpmm2ccd[cpmmNumber]);
128 
129  // In case we need to alter the order of the input list, keep a record
130  // of how the indices changed so we can rearrange the output list later
131  movedIndices.push_back(i);
132  }
133  catch (IException &e) {
134  QString msg = "The [" + imageList[i].toString() +
135  "] file is not a valid HiRise image";
136  throw IException(e, IException::User, msg, _FILEINFO_);
137  }
138  catch (...) {
139  // If any part of the above didn't work, we can safely assume the
140  // current file is not a valid HiRise image
141  QString msg = "The [" + imageList[i].toString() +
142  "] file is not a valid HiRise image";
143  throw IException(IException::User, msg, _FILEINFO_);
144  }
145  }
146 
147  // Error checking to ensure CCDID types match
148  for (int i = 0; i < imageList.size() - 1; i++) {
149  int id1 = getCCDType(ccds[i]);
150  int id2 = getCCDType(ccds[i + 1]);
151 
152  // CCDID types don't match
153  if (id1 != id2) {
154  string msg = "The list of input images must be all RED, all IR, or ";
155  msg += "all BG";
156  throw IException(IException::User, msg, _FILEINFO_);
157  }
158  }
159 
160  // Insertion sorts a list of filenames by their CCD numbers
161  for (int i = 1; i < imageList.size(); i++) {
162  QString temp = imageList[i].toString();
163  int ccd1 = ccds[i];
164  int movedIndex = movedIndices[i];
165 
166  int j = i - 1;
167  int ccd2 = ccds[j];
168 
169  while (j >= 0 && ccd2 > ccd1) {
170  setInput(j + 1, imageList[j].toString());
171  ccds[j + 1] = ccds[j];
172  movedIndices[j + 1] = movedIndices[j];
173 
174  j--;
175  if (j >= 0) ccd2 = ccds[j];
176  }
177 
178  setInput(j + 1, temp);
179  ccds[j + 1] = ccd1;
180  movedIndices[j + 1] = movedIndex;
181  }
182 
183  // Ensures BG and IR only have two files
184  if (ccds[0] == 10 || ccds[0] == 11) {
185  if (imageList.size() != 2) {
186  string msg = "A list of IR images must have exactly two ";
187  msg += "file names";
188  throw IException(IException::User, msg, _FILEINFO_);
189  }
190  }
191  else if (ccds[0] == 12 || ccds[0] == 13) {
192  if (imageList.size() != 2) {
193  string msg = "A list of BG images must have exactly two ";
194  msg += "file names";
195  throw IException(IException::User, msg, _FILEINFO_);
196  }
197  }
198  }
199 
200 
201  // CCD ID Type
202  int HiEqualization::getCCDType(int ccd) {
203  // Red, IR, or BG
204  return (ccd >= 0 && ccd <= 9) ? 0 : (ccd == 10 || ccd == 11) ? 1 : 2;
205  }
206 
207 
208  void HiEqualization::HiCalculateFunctor::addStats(Buffer &in) const {
209  Equalization::CalculateFunctor::addStats(in);
210 
211  // Number of samples per line that intersect with the next and the
212  // previous images. Check if samples equal 682 or 683. If not the above
213  // case, then we perform an algorithm to account for binning. Number of
214  // intersecting samples is directly related to total number of samples in
215  // the line, with 2048 being the maximum possible.
216  unsigned int intersect = (in.size() == 682 || in.size() == 683) ?
217  18 : (48 * in.size()) / 2048;
218 
219  m_statsLeft->AddData(&in[0], intersect);
220  m_statsRight->AddData(&in[in.size() - intersect], intersect);
221  }
222 
223 
224 }