OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimAtpTool.cpp
Go to the documentation of this file.
1 //**************************************************************************************************
2 //
3 // OSSIM Open Source Geospatial Data Processing Library
4 // See top level LICENSE.txt file for license information
5 //
6 //**************************************************************************************************
7 
8 #include "ossimAtpTool.h"
9 #include "../AtpCommon.h"
10 #include "AtpGenerator.h"
11 #include "AtpConfig.h"
12 #include "ossimCorrelationSource.h"
13 #include "ossimDescriptorSource.h"
15 
16 using namespace std;
17 using namespace ossim;
18 
19 namespace ATP
20 {
21 const char* ossimAtpTool::DESCRIPTION =
22  "Provides automatic tiepoint generation functionality. This tool uses JSON format to "
23  "communicate requests and results.";
24 
25 ossimAtpTool::ossimAtpTool()
26 : m_outputStream (0),
27  m_verbose (false),
28  m_featureBased (true),
29  m_algorithm (0),
30  m_method (METHOD_UNASSIGNED)
31 {
32 }
33 
35 {
36 }
37 
39 {
40  // Add global usage options. Don't include ossimChipProcUtil options as not appropriate.
42 
43  // Set the general usage:
45  ossimString usageString = ap.getApplicationName();
46  usageString += " atp [options] \n\n";
47  usageString +=
48  "Accesses automatic tiepoint generation functionality given JSON request on stdin (or input file if\n"
49  "-i specified). The response JSON is output to stdout unless -o option is specified.\n";
50  au->setCommandLineUsage(usageString);
51 
52  // Set the command line options:
53  au->addCommandLineOption("--algorithms",
54  "List available auto-tie-point algorithms");
55  au->addCommandLineOption("-i <filename>",
56  "Reads request JSON from the input file specified instead of stdin.");
57  au->addCommandLineOption("-o <filename>",
58  "Outputs response JSON to the output file instead of stdout.");
59  au->addCommandLineOption("--parameters",
60  "List all ATP parameters with default values.");
61  au->addCommandLineOption("-v",
62  "Verbose. All non-response (debug) output to stdout is enabled.");
63 }
64 
66 {
67  string ts1;
70 
71  if (!ossimTool::initialize(ap))
72  return false;
73  if (m_helpRequested)
74  return true;
75 
76  if ( ap.read("-v"))
77  m_verbose = true;
78 
79  if ( ap.read("--algorithms"))
81 
82  if ( ap.read("--parameters"))
84 
85  if ( ap.read("-i", sp1))
86  {
87  ifstream s (ts1);
88  if (s.fail())
89  {
90  CFATAL<<__FILE__<<" Could not open input file <"<<ts1<<">";
91  return false;
92  }
93  try
94  {
95  Json::Value queryJson;
96  s >> queryJson;
97  loadJSON(queryJson);
98  }
99  catch (exception& e)
100  {
101  CFATAL<<__FILE__<<" Could not parse input JSON <"<<ts1<<">";
102  return false;
103  }
104  }
105 
106  if ( ap.read("-o", sp1))
107  {
108  ofstream* s = new ofstream (ts1);
109  if (s->fail())
110  {
111  CFATAL<<__FILE__<<" Could not open output file <"<<ts1<<">";
112  return false;
113  }
114  m_outputStream = s;
115  }
116  else
117  m_outputStream = &clog;
118 
119  return true;
120 }
121 
122 void ossimAtpTool::loadJSON(const Json::Value& queryRoot)
123 {
124  ostringstream xmsg;
125  xmsg<<"ossimAtpTool::loadJSON() ";
126 
127  // Fetch the desired method from the JSON if provided, otherwise rely on command line options:
128  m_method = GENERATE;
129  string method = queryRoot["method"].asString();
130  if (method == "getAlgorithms")
132  else if (method == "getParameters")
134 
135  // Fetch the desired algorithm or configuration:
136  AtpConfig& config = AtpConfig::instance();
137  string algorithm = queryRoot["algorithm"].asString();
138  if (algorithm.empty())
139  {
140  // An optional field specifies a configuration that contains the base-name of a custom
141  // parameters JSON file including algorithm type. Read that if specified:
142  m_configuration = queryRoot["configuration"].asString();
143  if (!m_configuration.empty())
144  {
145  if (!config.readConfig(m_configuration))
146  {
147  xmsg << "Fatal error trying to read default ATP configuration for selected "
148  "configuration <"<<m_configuration<<">";
149  throw ossimException(xmsg.str());
150  }
151  algorithm = config.getParameter("algorithm").asString();
152  }
153  }
154  // Otherwise read the algorithm's default config params from the system:
155  else if (!config.readConfig(algorithm))
156  {
157  xmsg << "Fatal error trying to read default ATP configuration for selected algorithm <"
158  <<algorithm<<">";
159  throw ossimException(xmsg.str());
160  }
161 
162  // Assign enum data member used throughout the service:
163  if (algorithm == "crosscorr")
164  m_algorithm = (unsigned int) AtpGenerator::CROSSCORR;
165  else if (algorithm == "descriptor")
166  m_algorithm = (unsigned int) AtpGenerator::DESCRIPTOR;
167  else if (algorithm == "nasa")
168  m_algorithm = (unsigned int) AtpGenerator::NASA;
169  else
171 
172  // If parameters were provided in the JSON payload, have the config override the defaults:
173  const Json::Value& parameters = queryRoot["parameters"];
174  if (!parameters.isNull())
175  config.loadJSON(parameters);
176 
177  if (config.diagnosticLevel(2))
178  CINFO<<"\nATP configuration after loading:\n"<<config<<endl;
179 
180  if (m_method == GENERATE)
181  {
182  // Load the active photoblock from JSON.
183  // The root JSON object can optionally contain a photoblock with image list contained. If so,
184  // use that object to load images, otherwise use the root.
185  if (queryRoot.isMember("photoblock"))
186  m_photoBlock.reset(new PhotoBlock(queryRoot["photoblock"]));
187  else
188  m_photoBlock.reset(new PhotoBlock(queryRoot));
189  }
190 }
191 
193 {
194  ostringstream xmsg;
195 
196  try
197  {
198  switch (m_method)
199  {
200  case GET_ALGO_LIST:
201  getAlgorithms();
202  break;
203  case GET_PARAMS:
204  getParameters();
205  break;
206  case GENERATE:
207  generate();
208  break;
209  default:
210  xmsg << "Fatal: No method selected prior to execute being called. I don't know what to do!";
211  throw ossimException(xmsg.str());
212  }
213 
214  // Serialize JSON object for return:
215  if (m_outputStream)
216  (*m_outputStream) << m_responseJSON;
217  }
218  catch(ossimException &e)
219  {
220  CFATAL<<"Exception: "<<e.what()<<endl;
221  if (m_outputStream)
222  *m_outputStream<<"{ \"ERROR\": \"" << e.what() << "\" }\n"<<endl;
223  }
224 
225  // close any open file streams:
226  ofstream* so = dynamic_cast<ofstream*>(m_outputStream);
227  if (so)
228  {
229  so->close();
230  delete so;
231  }
232 
233  return true;
234 }
235 
237 {
238 }
239 
241 {
242  m_responseJSON.clear();
243 
244  Json::Value algoList;
245  algoList[0]["name"] = "crosscorr";
246  algoList[0]["description"] = "Matching by cross-correlation of raster patches";
247  algoList[0]["label"] = "Cross Correlation";
248  algoList[1]["name"] = "descriptor";
249  algoList[1]["description"] = "Matching by feature descriptors";
250  algoList[1]["label"] = "Descriptor";
251  //algoList[2]["name"] = "nasa";
252  //algoList[2]["description"] = "Tiepoint extraction using NASA tool.";
253  //algoList[2]["label"] = "NASA";
254 
255  m_responseJSON["algorithms"] = algoList;
256 }
257 
259 {
260  m_responseJSON.clear();
261 
262  Json::Value params;
263  AtpConfig::instance().saveJSON(params);
264 
265  m_responseJSON["parameters"] = params;
266 
267 }
268 
270 {
271  ostringstream xmsg;
272  xmsg<<"ossimAtpTool::generate() ";
273 
274  switch (m_algorithm)
275  {
276  case (unsigned int) AtpGenerator::CROSSCORR:
277  case (unsigned int) AtpGenerator::DESCRIPTOR:
279  break;
280  case (unsigned int) AtpGenerator::NASA:
281  xmsg << "NASA Algorithm not yet implemented!";
282  throw ossimException(xmsg.str());
283  break;
284  case (unsigned int) AtpGenerator::ALGO_UNASSIGNED:
285  default:
286  xmsg << "Fatal: No algorithm selected prior to execute being called. I don't know what to do!";
287  throw ossimException(xmsg.str());
288  }
289 }
290 
292 {
293  static const char* MODULE = "ossimAtpTool::doPairwiseMatching() ";
294  ostringstream xmsg;
295  xmsg<<MODULE;
296 
297  if (!m_photoBlock || (m_photoBlock->getImageList().size() < 2))
298  {
299  xmsg << "No photoblock has been declared or it has less than two images. Cannot perform ATP.";
300  throw ossimException(xmsg.str());
301  }
302 
303  shared_ptr<AtpGenerator> generator;
304 
305  // First obtain list of images from photoblock:
306  std::vector<shared_ptr<Image> >& imageList = m_photoBlock->getImageList();
307  int numImages = (int) imageList.size();
308  for (int i=0; i<(numImages-1); i++)
309  {
310  shared_ptr<Image> imageA = imageList[i];
311  for (int j=i+1; j<numImages; j++)
312  {
313  shared_ptr<Image> imageB = imageList[j];
314 
315  // Instantiate the ATP generator for this pair:
316  generator.reset(new AtpGenerator((AtpGenerator::Algorithm) m_algorithm));
317 
318  // Generate tie points using A for features:
319  generator->setRefImage(imageA);
320  generator->setCmpImage(imageB);
321  TiePointList tpList;
322  generator->generateTiePointList(tpList);
323  m_photoBlock->addTiePoints(tpList);
324 
325  if (AtpConfig::instance().diagnosticLevel(2))
326  CINFO<<"Completed pairwise match for pair "<<i<<"-"<<j<<endl;
327 
328  // Now reverse CMP and REF to find possible additional features on B:
329  bool doTwoWaySearch = AtpConfig::instance().getParameter("doTwoWaySearch").asBool();
330  if (doTwoWaySearch)
331  {
332  generator->setRefImage(imageB);
333  generator->setCmpImage(imageA);
334  tpList.clear();
335  generator->generateTiePointList(tpList);
336  m_photoBlock->addTiePoints(tpList);
337 
338  if (AtpConfig::instance().diagnosticLevel(2))
339  CINFO<<"Completed pairwise match for pair "<<j<<"-"<<i<<endl;
340  }
341  }
342  }
343 
344  // Save list to photoblock JSON:
345  Json::Value pbJson;
346  m_photoBlock->saveJSON(pbJson);
347  m_responseJSON["photoblock"] = pbJson;
348 
349  if (AtpConfig::instance().diagnosticLevel(1))
350  CINFO<<"\n"<<MODULE<<"Total TPs found = "<<m_photoBlock->getTiePointList().size()<<endl;
351 }
352 
353 
354 }
355 
356 
std::string getApplicationName() const
return the application name, as specified by argv[0]
JsonParam & getParameter(const char *paramName)
Returns a parameter (might be a null parameter if paramName not found in the configuration.
Definition: JsonConfig.cpp:377
void addCommandLineOption(const ossimString &option, const ossimString &explanation)
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
std::ostream * m_outputStream
Definition: ossimAtpTool.h:55
std::string m_configuration
Definition: ossimAtpTool.h:60
virtual void setUsage(ossimArgumentParser &ap)
Initializes the aurgument parser with expected parameters and options.
Represents serializable keyword/value map.
bool m_helpRequested
Definition: ossimTool.h:150
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
bool read(const std::string &str)
search for an occurance of a string in the argument list, on sucess remove that occurance from the li...
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
virtual bool execute()
Writes product to output file if applicable.
unsigned int m_algorithm
Definition: ossimAtpTool.h:58
Class for representing MSP PhotoBlock.
Definition: PhotoBlock.h:25
void setCommandLineUsage(const ossimString &explanation)
ossimApplicationUsage * getApplicationUsage()
virtual void saveJSON(Json::Value &params_json_node) const
Reads the params controlling the process from the JSON node named "parameters".
Definition: JsonConfig.cpp:447
std::string asString() const
Definition: JsonConfig.cpp:285
virtual void getKwlTemplate(ossimKeywordlist &kwl)
Assigns a template keywordlist to string for initializing derived classes.
std::vector< std::shared_ptr< TiePoint > > TiePointList
Definition: TiePoint.h:21
virtual void setUsage(ossimArgumentParser &ap)
Initializes the aurgument parser with expected parameters and options.
Definition: ossimTool.cpp:41
virtual const char * what() const
Returns the error message.
Base class for OSSIM-based ATP generators.
Definition: AtpGenerator.h:33
bool asBool() const
Definition: JsonConfig.cpp:257
virtual bool initialize(ossimArgumentParser &ap)
Initializes from command line arguments.
virtual bool initialize(ossimArgumentParser &ap)
Initializes from command line arguments.
Definition: ossimTool.cpp:58
THESE FUNCTIONS REQUIRE OPENCV.
bool diagnosticLevel(unsigned int level) const
Convenience method returns TRUE if the currently set diagnostic level is <= level.
Definition: JsonConfig.cpp:461
virtual void loadJSON(const Json::Value &json)
Reads processing params from JSON object provided.
Json::Value m_responseJSON
Definition: ossimAtpTool.h:61
std::shared_ptr< ossim::PhotoBlock > m_photoBlock
Definition: ossimAtpTool.h:62
#define CFATAL
static AtpConfig & instance()
Singleton implementation.
Definition: AtpConfig.cpp:20
virtual ~ossimAtpTool()
std::basic_ofstream< char > ofstream
Class for char output file streams.
Definition: ossimIosFwd.h:47
#define CINFO
virtual void loadJSON(const Json::Value &params_json_node)
Reads the params controlling the process from the JSON node named "parameters".
Definition: JsonConfig.cpp:403
void doPairwiseMatching()
When the ATP generator works with image pairs (crosscorr and descriptor), This method is used to loop...
bool readConfig(const std::string &configName="")
Definition: AtpConfig.cpp:38
Singleton class maintaining parameters affecting the automatic tie point generation.
Definition: AtpConfig.h:24