Skip to content
Snippets Groups Projects
Unverified Commit 4a13290e authored by Stuart Sides's avatar Stuart Sides Committed by GitHub
Browse files

Add support for Mars Express HRSC SRC instrument (#3826)


* Add support for MacOS 10.14, needed for make base tests

* Add support for MEX SRC instrument

* Fixs found by PR review

* Fixed PR issues

* Tweaking translation

* Added exposure duration

* Adding in the SRC model

* Now with lat/lon, and test updates

* Adding Mex SRC Camera unitest

* Fix spelling in application docs.

Co-authored-by: default avatarKristin <kberry@usgs.gov>
parent 3ad04cd8
No related branches found
No related tags found
No related merge requests found
Showing
with 689 additions and 223 deletions
Group = Keyword1
Auto
InputKey = SpacecraftName
InputGroup = "IsisCube,Instrument"
InputPosition = (IsisCube, Instrument)
OutputName = Keyword1
OutputPosition = (Group, SerialNumberKeywords)
Translation = (MEX, "MARS EXPRESS")
Translation = (MEX, MARS_EXPRESS)
Translation = (*, *)
End_Group
Group = Keyword2
Auto
InputKey = SpacecraftClockStartCount
InputGroup = "IsisCube,Instrument"
InputPosition = (IsisCube, Instrument)
OutputName = Keyword2
OutputPosition = (Group, SerialNumberKeywords)
Translation = (*, *)
End_Group
Group = Keyword3
Auto
InputKey = InstrumentId
InputGroup = "IsisCube,Instrument"
InputPosition = (IsisCube, Instrument)
OutputName = Keyword3
OutputPosition = (Group, SerialNumberKeywords)
Translation = (*, *)
End_Group
Group = Keyword4
Auto
InputKey = DetectorId
InputGroup = "IsisCube,Archive"
InputPosition = (IsisCube, Archive)
OutputName = Keyword4
OutputPosition = (Group, SerialNumberKeywords)
Translation = (*, *)
End_Group
End
......@@ -108,6 +108,7 @@ Group = InstrumentName
# MEX
Translation = (Hrsc, HRSC)
Translation = (Src, SRC)
# Messenger
Translation = (Mdis, MDIS-NAC)
......
#
# The group names listed here are the native names used by
# applications to get the foreign names and values
#
# There is only one level of groups the groups are not
# allowed to be nested
#
# The Group names can NOT be repeated.
#
# InputGroup is a comma delimited list of objects and/or
# groups in the foreign label. Traversing this list will
# lead to the correct level to find the foreign keyword.
#
# InputKey is the keyword within the group which holds
# the information.
#
# InputDefault is the value used if there is no value for
# the keyword
#
# Translation is the native and corresponding foreign values.
# Translation may be repeated as needed.
#
# Translations for HRSC Stereo and SRC instrument.
# ISIS cube label Archive group
Group = DataSetId
Auto
InputKey = DATA_SET_ID
......
#
# The group names listed here are the native names used by
# applications to get the foreign names and values
#
# There is only one level of groups the groups are not
# allowed to be nested
#
# The Group names can NOT be repeated.
#
# InputGroup is a comma delimited list of objects and/or
# groups in the foreign label. Traversing this list will
# lead to the correct level to find the foreign keyword.
#
# InputKey is the keyword within the group which holds
# the information.
#
# InputDefault is the value used if there is no value for
# the keyword
#
# Translation is the native and corresponding foreign values.
# Translation may be repeated as needed.
#
# Translations for HRSC Stereo and SRC instrument.
# ISIS cube label BandBin group
Group = FilterWidth
Auto
InputKey = BANDWIDTH
OutputName = Width
OutputPosition = (Group, BandBin)
Translation = (*, *)
Translation = ("--- Illegal Value ---", *)
End_Group
Group = FilterCenter
......@@ -35,6 +15,5 @@ Group = FilterCenter
OutputName = Center
OutputPosition = (Group, BandBin)
Translation = (*, *)
Translation = ("--- Illegal Value ---", *)
End_Group
End
#
# The group names listed here are the native names used by
# applications to get the foreign names and values
#
# There is only one level of groups the groups are not
# allowed to be nested
#
# The Group names can NOT be repeated.
#
# InputGroup is a comma delimited list of objects and/or
# groups in the foreign label. Traversing this list will
# lead to the correct level to find the foreign keyword.
#
# InputKey is the keyword within the group which holds
# the information.
#
# InputDefault is the value used if there is no value for
# the keyword
#
# Translation is the native and corresponding foreign values.
# Translation may be repeated as needed.
#
# Translations for HRSC Stereo and SRC instrument.
# ISIS cube label Instrument group
Group = SpacecraftName
Auto
InputKey = INSTRUMENT_HOST_NAME
......@@ -31,10 +12,20 @@ End_Group
Group = InstrumentId
Auto
InputKey = INSTRUMENT_ID
InputKey = DETECTOR_ID
OutputName = InstrumentId
OutputPosition = (Group, Instrument)
Translation = (*, *)
Translation = (HRSC, "MEX_HRSC_HEAD")
Translation = (HRSC, "MEX_HRSC_S2")
Translation = (HRSC, "MEX_HRSC_RED")
Translation = (HRSC, "MEX_HRSC_P2")
Translation = (HRSC, "MEX_HRSC_BLUE")
Translation = (HRSC, "MEX_HRSC_NADIR")
Translation = (HRSC, "MEX_HRSC_GREEN")
Translation = (HRSC, "MEX_HRSC_P1")
Translation = (HRSC, "MEX_HRSC_IR")
Translation = (HRSC, "MEX_HRSC_S1")
Translation = (SRC, "MEX_HRSC_SRC")
End_Group
Group = StartTime
......@@ -88,6 +79,24 @@ Group = TargetName
Translation = (Cal, CAL)
End_Group
Group = Summing
Auto
Optional
InputKey = MACROPIXEL_SIZE
OutputName = Summing
OutputPosition = (Group, Instrument)
Translation = (*, *)
End_Group
Group = ExpousreDuration
Auto
Optional
InputKey = EXPOSURE_DURATION
OutputName = ExposureDuration
OutputPosition = (Group, Instrument)
Translation = (*, *)
End_Group
Group = FocalPlaneTemperature
Auto
Optional
......
# Translations for HRSC Stereo and SRC instrument.
# ISIS cube label Kernels group
Group = NaifIkCode
Auto
InputKey = DETECTOR_ID
OutputName = NaifIkCode
OutputPosition = (Group, Kernels)
Translation = (-41210, "MEX_HRSC_HEAD")
Translation = (-41211, "MEX_HRSC_S2")
Translation = (-41212, "MEX_HRSC_RED")
Translation = (-41213, "MEX_HRSC_P2")
Translation = (-41214, "MEX_HRSC_BLUE")
Translation = (-41215, "MEX_HRSC_NADIR")
Translation = (-41216, "MEX_HRSC_GREEN")
Translation = (-41217, "MEX_HRSC_P1")
Translation = (-41218, "MEX_HRSC_IR")
Translation = (-41219, "MEX_HRSC_S1")
Translation = (-41220, "MEX_HRSC_SRC")
End_Group
......@@ -5,18 +5,26 @@
<brief>Import HRSC image</brief>
<description>
This program imports Mars Express HRSC files. This works by first
determining whether or not the input file has prefix data. If there is
prefix data, the prefix data is collected and used to look for "gaps" - HRSC
files can give us a time and exposure duration for each line, we look for
where the time + exposure duration =/= next line's time. We populate a
table (LineScanTimes) with the prefix data and lineInFile with whether or
not a gap should be inserted. For all files, we now process the data and if
there were gaps, they will be put in their proper places. This is a two-pass
system for files with prefix data, one-pass for files without. The Isis2
equivalent to this program is mex2isis.pl. It is worth noting that
regardless of the input file's byte order, the prefix data byte order is
always LSB.
<p>
This program imports Mars Express HRSC files. This includes both the HRSC
Stereo and the SRC instruments with procesing level of "1" or "2" (not "3").
The program populates all label keywords necessary to create the corresponding camera
models.
</p>
<p>
For the stereo instrument there is always prefix data. The
prefix data is collected and used to look for "gaps" aka missing lines. The
line prefix data for HRSC
files contain time and exposure duration for each line. We look for occurrences
where the time + exposure duration is not equal to the next line's time to find missing
lines. This program uses two passes, the first reads the PDS file into a cube, the
second inserts lines where gaps were identified.
</p>
<p>
For the SRC instrument, this program reads the PDS file and converts it to an ISIS cube. The
PDS file for the SRC instrument is much simpler than the stereo instrument files and requires
no special processing.
</p>
</description>
<history>
......@@ -40,6 +48,9 @@
Updated the error messages thrown when hrsc2isis trys to ingest an image that is not an HRSC
image, and when hrsc2isis trys to ingest a map projected image. Fixes #4259.
</change>
<change name="Stuart Sides" date="2020-03-31">
Added ability to read HRSC SRC images
</change>
</history>
<oldName>
......@@ -57,7 +68,7 @@
<type>filename</type>
<fileMode>input</fileMode>
<brief>
Input HRSC Image
Input HRSC Stereo or SRC Image
</brief>
<description>
Use this parameter to select the PDS filename. This file
......@@ -68,7 +79,7 @@
binary image data.
</description>
<filter>
*.lbl *.img
*.lbl *.LBL *.img *.IMG
</filter>
</parameter>
......@@ -90,10 +101,10 @@
<examples>
<example>
<brief>Import an HRSC image with gaps</brief>
<brief>Import an HRSC stereo instrument image with gaps</brief>
<description>
This example covers importing an HRSC image and shows what happens when
gaps are found.
This example covers importing an HRSC stereo instrument image and shows
what happens when gaps are found.
</description>
<terminalInterface>
<commandLine> from=h0279_0000_re2.img to=h0279_0000_re2.cub</commandLine>
......
......@@ -11,93 +11,146 @@
using namespace std;
using namespace Isis;
void IgnoreData(Isis::Buffer &buf) {};
void ImportHrscStereoImage(ProcessImportPds &p, Pvl &label);
void ImportHrscSrcImage(ProcessImportPds &p, Pvl &label);
void IgnoreData(Isis::Buffer &buf);
void WriteOutput(Isis::Buffer &buf);
void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel);
Cube *outCube = NULL;
long numLinesSkipped = 0;
std::vector< bool > lineInFile;
/**
* This program imports Mars Express HRSC files
*
* This works by first determining whether or not the input file
* has prefix data.
*
* If there is prefix data, a StartProcess is called with the
* IgnoreData() function callback in order to get the import class to
* collect prefix data. Once the prefix data is populated, we go ahead
* and look for "gaps" - HRSC files can give us a time and exposure duration
* for each line, we look for where the time + exposure duration != next line's time.
* We populate a table (LineScanTimes) with the prefix data and lineInFile with whether or not
* a gap should be inserted.
*
* For all files, we now process the data using the WriteOutput callback. If there were gaps,
* WriteOutput will put them in their proper places. Finally, we translate the labels and put
* the LineScanTimes (if necessary) in the output cube.
*
* This is a two-pass system for files with prefix data, one-pass for files without.
*
* The Isis2 equivalent to this program is mex2isis.pl. It is worth noting that regardless of the
* input file's byte order, the prefix data byte order is always LSB.
*/
void IsisMain() {
UserInterface &ui = Application::GetUserInterface();
try {
Pvl temp(ui.GetFileName("FROM"));
// Check for HRSC file
if(temp["INSTRUMENT_ID"][0] != "HRSC") throw IException();
ProcessImportPds p;
Pvl label;
p.SetPdsFile(ui.GetFileName("FROM"), "", label);
// Decide if the file is an HRSC image or something else
if (label["INSTRUMENT_ID"][0] != "HRSC") {
IString msg = "File [" + ui.GetFileName("FROM") + "] with [INSTRUMENT_ID = " +
label["INSTRUMENT_ID"][0] +
"] does not appear to be a Mars Express HRSC image. " +
"Consider using pds2isis to import the image.";
throw IException(IException::User, msg, _FILEINFO_);
}
catch(IException &e) {
IString msg = "File [" + ui.GetFileName("FROM") +
"] does not appear to be a Mars Express HRSC image.";
// Decide if the file is an HRSC SRC, HRSC Stereo (S2) or something else
bool isSrcFile;
if (label["DETECTOR_ID"][0] == "MEX_HRSC_SRC") {
isSrcFile = true;
}
else if ((label["DETECTOR_ID"][0] == "MEX_HRSC_S2") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_RED") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_P2") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_BLUE") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_NADIR") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_GREEN") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_P1") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_IR") ||
(label["DETECTOR_ID"][0] == "MEX_HRSC_S1")) {
isSrcFile = false;
}
else {
QString msg = "File [" + ui.GetFileName("FROM");
msg += "] does not appear to be a Mars Express stereo or SRC file. Label keyword [DETECTOR_ID = ";
msg += label["DETECTOR_ID"][0] + "] is not recognized.";
throw IException(IException::User, msg, _FILEINFO_);
}
ProcessImportPds p;
Pvl label;
lineInFile.clear();
numLinesSkipped = 0;
// This program is setup to work with Mex HRSC processing level 1 and 2 only.
// Not level 3 (Mapped)
if ((int)label["PROCESSING_LEVEL_ID"] >= 3) {
QString msg = "File [" + ui.GetFileName("FROM");
msg += "] has keyword [PROCESSING_LEVEL_ID = " + label["PROCESSING_LEVEL_ID"][0] + "]";
msg += " and can not be read by this program.";
throw IException(IException::User, msg, _FILEINFO_);
}
p.SetPdsFile(ui.GetFileName("FROM"), "", label);
// The processing for Stereo and SRC are significantly different. Call the
// appropriate processing function
if (isSrcFile) {
ImportHrscSrcImage(p, label);
}
else {
ImportHrscStereoImage(p, label);
}
CubeAttributeOutput outAtt(ui.GetFileName("TO"));
outCube = new Cube();
outCube->setByteOrder(outAtt.byteOrder());
outCube->setFormat(outAtt.fileFormat());
outCube->setLabelsAttached(outAtt.labelAttachment() == AttachedLabel);
}
/**
* Isis2 mex2isis.pl:
* if (index($detector_id,"MEX_HRSC_SRC") < 0 &&
* $processing_level_id < 3)
*/
bool isSrcFile = (label["DETECTOR_ID"][0] != "MEX_HRSC_SRC");
bool mapProjRdr = ((int)label["PROCESSING_LEVEL_ID"] >= 3);
// Import a PDS3, HRSC, SRC Camera image.
void ImportHrscSrcImage(ProcessImportPds &p, Pvl &label) {
try {
if (!isSrcFile) {
QString msg = "File [" + ui.GetFileName("FROM");
msg += "] is SRC data and cannot be read.";
throw IException(IException::User, msg, _FILEINFO_);
outCube = p.SetOutputCube("TO");
p.StartProcess();
Pvl otherLabels;
TranslateHrscLabels(label, otherLabels);
if (otherLabels.hasGroup("Instrument") &&
(otherLabels.findGroup("Instrument").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("Instrument"));
}
if (mapProjRdr) {
QString msg = "File [" + ui.GetFileName("FROM");
msg += "] is map projected and cannot be read.";
throw IException(IException::User, msg, _FILEINFO_);
if (otherLabels.hasGroup("BandBin") &&
(otherLabels.findGroup("BandBin").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("BandBin"));
}
if (otherLabels.hasGroup("Archive") &&
(otherLabels.findGroup("Archive").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("Archive"));
}
catch (IException &e) {
QString msg = "File cannot be read by hrsc2isis, use pds2isis.";
throw IException(e, IException::User, msg, _FILEINFO_);
if (otherLabels.hasGroup("Kernels") &&
(otherLabels.findGroup("Kernels").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("Kernels"));
}
p.EndProcess();
}
/**
* This function reads Mars Express HRSC Stereo files
*
* First pass through the file is a Process called with the IgnoreData() function in order to
* get the import class to collect prefix data. Once the prefix data is populated, we look for
* "gaps" - HRSC files with prefix data give us a time and exposure duration for each line, we
* look for where the time + exposure duration != next line's time. We populate a table
* (LineScanTimes) with the prefix data and lineInFile with whether or not a missing line should
* be inserted.
*
* Second pass through the file is a Process called with the WriteOutput function. If there were
* gaps, WriteOutput will add lines at the appropriate positions in the output cube. Finally, we
* translate the labels and put the LineScanTimes (if necessary) in the output cube.
*
* This is a two-pass system for files with prefix data, one-pass for files without.
*
* NOTE: Regardless of the input file's byte order IMAGE-SAMPLE_TYPE, the prefix data byte order
* is always LSB.
*/
void ImportHrscStereoImage(ProcessImportPds &p, Pvl &label) {
UserInterface &ui = Application::GetUserInterface();
lineInFile.clear();
numLinesSkipped = 0;
CubeAttributeOutput outAtt(ui.GetFileName("TO"));
outCube = new Cube();
outCube->setByteOrder(outAtt.byteOrder());
outCube->setFormat(outAtt.fileFormat());
outCube->setLabelsAttached(outAtt.labelAttachment() == AttachedLabel);
TableField ephTimeField("EphemerisTime", TableField::Double);
TableField expTimeField("ExposureTime", TableField::Double);
TableField lineStartField("LineStart", TableField::Integer);
......@@ -115,6 +168,7 @@ void IsisMain() {
p.Progress()->SetText("Reading Prefix Data");
p.StartProcess(IgnoreData);
// Get the prefix data from the Process
// The prefix data is always in LSB format, regardless of the overall file format
EndianSwapper swapper("LSB");
......@@ -169,17 +223,11 @@ void IsisMain() {
outCube->write(timesTable);
// Get as many of the other labels as we can
// Translate the PDS labels into ISIS labels and add them to the cube
Pvl otherLabels;
//p.TranslatePdsLabels (otherLabels);
TranslateHrscLabels(label, otherLabels);
if(otherLabels.hasGroup("Mapping") &&
(otherLabels.findGroup("Mapping").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("Mapping"));
}
if (otherLabels.hasGroup("Instrument") &&
(otherLabels.findGroup("Instrument").keywords() > 0)) {
outCube->putGroup(otherLabels.findGroup("Instrument"));
......@@ -208,7 +256,19 @@ void IsisMain() {
lineInFile.clear();
}
// Processing function called by ProcessImportPds:StartProcess for each HRSC Stereo instrumennt
// line. It ignores the image data and returns. This is used to get the ProcessImportPds object
// to collect the prefix bytes.
void IgnoreData(Isis::Buffer &buf) {
return;
}
// Processing function called by ProcessImportPds:StartProcess for each HRSC Stereo instrument
// line in the IMG file.
void WriteOutput(Isis::Buffer &buf) {
LineManager outLines(*outCube);
if (lineInFile.size()) {
......@@ -225,15 +285,20 @@ void WriteOutput(Isis::Buffer &buf) {
outLines.SetLine(buf.Line() + numLinesSkipped, buf.Band());
// outLines.Copy(buf); doesn't work because the raw buffers don't match
for(int i = 0; i < outLines.size(); i++)
for (int i = 0; i < outLines.size(); i++) {
outLines[i] = buf[i];
}
outCube->write(outLines);
return;
}
// Translate HRSC Stereo lables into ISIS labels
void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel) {
// Get the directory where the MRO HiRISE translation tables are.
// Get the directory where the translation tables are.
QString transDir = "$ISISROOT/appdata/translations/";
// Translate the Instrument group
......@@ -241,13 +306,6 @@ void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel) {
PvlToPvlTranslationManager instrumentXlater(inLabels, transFile.expanded());
instrumentXlater.Auto(outLabel);
if(inLabels.hasKeyword("MACROPIXEL_SIZE")) {
outLabel.findGroup("Instrument", Pvl::Traverse) += PvlKeyword("Summing", inLabels["MACROPIXEL_SIZE"][0]);
}
else {
outLabel.findGroup("Instrument", Pvl::Traverse) += PvlKeyword("Summing", "1");
}
// Remove 'Z' from times
QString startTime = outLabel.findGroup("Instrument", Pvl::Traverse)["StartTime"][0];
startTime = startTime.mid(0, startTime.size() - 1);
......@@ -267,30 +325,9 @@ void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel) {
PvlToPvlTranslationManager archiveXlater(inLabels, transFile.expanded());
archiveXlater.Auto(outLabel);
std::map<QString, int> naifIkCodes;
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_HEAD", -41210));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_S2", -41211));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_RED", -41212));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_P2", -41213));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_BLUE", -41214));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_NADIR", -41215));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_GREEN", -41216));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_P1", -41217));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_IR", -41218));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_S1", -41219));
naifIkCodes.insert(std::pair<QString, int>("MEX_HRSC_SRC", -41220));
QString key = outLabel.findGroup("Archive", Pvl::Traverse)["DetectorId"];
int ikCode = naifIkCodes[key];
if(ikCode < -41220 || ikCode > -41210) {
QString msg = "Unrecognized Detector ID [";
msg += key;
msg += "]";
throw IException(IException::Unknown, msg, _FILEINFO_);
}
// Translate the Kernels group
transFile = transDir + "MexHrscKernels.trn";
PvlToPvlTranslationManager kernelsXlater(inLabels, transFile.expanded());
kernelsXlater.Auto(outLabel);
PvlGroup kerns("Kernels");
kerns += PvlKeyword("NaifIkCode", toString(ikCode));
outLabel.addGroup(kerns);
}
......@@ -6,6 +6,7 @@ commands:
$(APPNAME) FROM=$(INPUT)/h0279_0000_re2.img TO=$(OUTPUT)/h0279_0000_re2.cub > /dev/null;
tabledump FROM=$(OUTPUT)/h0279_0000_re2.cub TO=$(OUTPUT)/h0279_0000_re2.txt NAME=LineScanTimes > /dev/null;
catlab FROM=$(OUTPUT)/h0279_0000_re2.cub to=$(OUTPUT)/h0279_0000_re2.pvl > /dev/null;
if [ `$(APPNAME) FROM=$(INPUT)/h1580_0008_sr3.img \
TO=$(OUTPUT)/junk.cub \
>& $(OUTPUT)/error_message_temp.txt` ]; \
......@@ -13,3 +14,4 @@ commands:
fi;
$(SED) 's+\[/.*/input/+\[input/+' $(OUTPUT)/error_message_temp.txt > $(OUTPUT)/error.txt;
$(RM) $(OUTPUT)/error_message_temp.txt;
......@@ -2,13 +2,8 @@ APPNAME =hrsc2isis
include $(ISISROOT)/make/isismake.tsts
commands:# TEST A: Check that a projected HRSC image fails to be read
echo -e "Test hrsc2isis with an image that has SRC data:" > $(OUTPUT)/error_message_temp.txt;
if [ `$(APPNAME) \
FROM=$(INPUT)/h2862_0006_sr2.img \
TO=$(OUTPUT)/temp.cub \
2>> $(OUTPUT)/error_message_temp.txt > /dev/null` ]; \
then true; \
fi;
$(SED) 's+\[/.*/input/+\[input/+' $(OUTPUT)/error_message_temp.txt > $(OUTPUT)/error_message.txt;
$(RM) $(OUTPUT)/error_message_temp.txt;
commands:
$(APPNAME) FROM=$(INPUT)/h2862_0006_sr2.img \
TO=$(OUTPUT)/h2862_0006_sr2.cub \
> /dev/null
Group = MarsExpress/Src
Version = 1
Library = MexHrscSrcCamera
Routine = MexHrscSrcCameraPlugin
EndGroup
/**
* @file
*
* Unless noted otherwise, the portions of Isis written by the USGS are public
* domain. See individual third-party library and package descriptions for
* intellectual property information,user agreements, and related information.
*
* Although Isis has been used by the USGS, no warranty, expressed or implied,
* is made by the USGS as to the accuracy and functioning of such software
* and related material nor shall the fact of distribution constitute any such
* warranty, and no responsibility is assumed by the USGS in connection
* therewith.
*
* For additional information, launch
* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see
* the Privacy &amp; Disclaimers page on the Isis website,
* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
* http://www.usgs.gov/privacy.html.
*/
#include "MexHrscSrcCamera.h"
#include <QString>
#include "CameraDetectorMap.h"
#include "CameraDistortionMap.h"
#include "CameraFocalPlaneMap.h"
#include "CameraGroundMap.h"
#include "CameraSkyMap.h"
#include "IString.h"
#include "iTime.h"
#include "NaifStatus.h"
using namespace std;
namespace Isis {
/**
* Constructs an Mex HRSC SRC Framing Camera object.
*
* @param lab Pvl label from a Mex HRSC SRC Framing Camera image.
*
* @author Stuart Sides
*
* @internal
*/
MexHrscSrcCamera::MexHrscSrcCamera(Cube &cube) : FramingCamera(cube) {
m_instrumentNameLong = "Super Resolution Channel";
m_instrumentNameShort = "SRC";
m_spacecraftNameLong = "Mars Express";
m_spacecraftNameShort = "MEX";
NaifStatus::CheckErrors();
SetFocalLength(Spice::getDouble("INS" + toString(naifIkCode()) + "_FOCAL_LENGTH"));
// For setting the pixel pitch, the Naif keyword PIXEL_SIZE is used instead of the ISIS
// default of PIXEL_PITCH, so set the value directly.
QString pp = "INS" + toString(naifIkCode()) + "_PIXEL_SIZE";
double pixelPitch = Spice::getDouble(pp);
pixelPitch /= 1000.0;
SetPixelPitch(pixelPitch);
// SRC doesn't appear to use any summing modes
CameraDetectorMap *detectorMap = new CameraDetectorMap(this);
detectorMap->SetDetectorSampleSumming(1);
detectorMap->SetDetectorLineSumming(1);
// Setup focal plane map. The class will read data from the instrument addendum kernel to pull
// out the affine transforms from detector samp,line to focal plane x,y.
CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this, naifIkCode());
// The boresight position recorded in the IK is zero-based and therefore needs to be adjusted
// for ISIS
double boresightSample = Spice::getDouble("INS" + toString(naifIkCode()) + "_CCD_CENTER",0) + 1.0;
double boresightLine = Spice::getDouble("INS" + toString(naifIkCode()) + "_CCD_CENTER",1) + 1.0;
focalMap->SetDetectorOrigin(boresightSample,boresightLine);
// The distortion is documented as near 1 pixel at the corners. This is less than the
// point spread, so zero distortion is used
new CameraDistortionMap(this);
// Setup the ground and sky map
new CameraGroundMap(this);
new CameraSkyMap(this);
// The observation start time and clock count for SRC are based on the center of the exposure.
Pvl &lab = *cube.label();
PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
QString clockCount = inst["SpacecraftClockStartCount"];
double et = getClockTime(clockCount).Et();
double exposureDuration = (double)inst["ExposureDuration"] / 1000.0;
pair<iTime, iTime> startStop = ShutterOpenCloseTimes(et, exposureDuration);
setTime(et);
// Internalize all the NAIF SPICE information into memory.
LoadCache();
NaifStatus::CheckErrors();
}
/**
* Returns the shutter open and close times.
*
* @param time The SpacecraftClockStartCount converted to ephemeris time.
* @param exposureDuration ExposureDuration keyword value from the labels, converted to
* seconds.
*
* @return @b pair < @b iTime, @b iTime > The first value is the shutter
* open time and the second is the shutter close time.
*
*/
pair<iTime, iTime> MexHrscSrcCamera::ShutterOpenCloseTimes(double time,
double exposureDuration) {
return FramingCamera::ShutterOpenCloseTimes(time - exposureDuration / 2.0, exposureDuration);
}
}
/**
* This is the function that is called in order to instantiate a MexHrscSrcCamera
* object.
*
* @param lab Cube labels
*
* @return Isis::Camera* MexHrscSrcCamera
*/
extern "C" Isis::Camera *MexHrscSrcCameraPlugin(Isis::Cube &cube) {
return new Isis::MexHrscSrcCamera(cube);
}
#ifndef MexHrscSrcCamera_h
#define MexHrscSrcCamera_h
/**
* @file
*
* Unless noted otherwise, the portions of Isis written by the USGS are public
* domain. See individual third-party library and package descriptions for
* intellectual property information,user agreements, and related information.
*
* Although Isis has been used by the USGS, no warranty, expressed or implied,
* is made by the USGS as to the accuracy and functioning of such software
* and related material nor shall the fact of distribution constitute any such
* warranty, and no responsibility is assumed by the USGS in connection
* therewith.
*
* For additional information, launch
* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see
* the Privacy &amp; Disclaimers page on the Isis website,
* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
* http://www.usgs.gov/privacy.html.
*/
#include "FramingCamera.h"
#include <QString>
namespace Isis {
/**
* This is the camera model for the Mex HRSC SRC Framing Camera
*
* @ingroup SpiceInstrumentsAndCameras
* @ingroup Mex
*
* @author 2020-04-02 Stuart Sides
*
* @internal
* @history 2020-04-01 Stuart Sides - Initial version
*/
class MexHrscSrcCamera : public FramingCamera {
public:
//! Create a MexHrscSrcCamera object
MexHrscSrcCamera(Cube &cube);
//! Destroys the MexHrscSrcCamera object
~MexHrscSrcCamera() {};
/**
* Reimplemented from FrameCamera
*
* @param time Start time of the observation
* @param exposureDuration The exposure duration of the observation
*
* @return std::pair<iTime,iTime> The start and end times of the observation
*/
virtual std::pair <iTime, iTime> ShutterOpenCloseTimes(double time,
double exposureDuration);
/**
* CK frame ID - - Instrument Code from spacit run on CK
*
* @return @b int The appropriate instrument code for the "Camera-matrix"
* Kernel Frame ID
*/
virtual int CkFrameId() const { return (-41001); }
/**
* CK Reference ID - J2000
*
* @return @b int The appropriate instrument code for the "Camera-matrix"
* Kernel Reference ID
*/
virtual int CkReferenceId() const { return (1); }
/**
* SPK Reference ID - J2000
*
* @return @b int The appropriate instrument code for the Spacecraft
* Kernel Reference ID
*/
virtual int SpkReferenceId() const { return (1); }
};
};
#endif
Unit Test for MexHrscSrcCamera...
FileName: H0010_0023_SR2.cub
CK Frame: -41220
Kernel IDs:
CK Frame ID = -41001
CK Reference ID = 1
SPK Target ID = -41
SPK Reference ID = 1
Spacecraft Name Long: Mars Express
Spacecraft Name Short: MEX
Instrument Name Long: Super Resolution Channel
Instrument Name Short: SRC
For upper left corner ...
DeltaSample = 0.000000000
DeltaLine = 0.000000000
For upper right corner ...
DeltaSample = 0.000000000
DeltaLine = 0.000000000
For lower left corner ...
DeltaSample = 0.000000000
DeltaLine = 0.000000000
For lower right corner ...
DeltaSample = 0.000000000
DeltaLine = 0.000000000
For center pixel position ...
Latitude OK
Longitude OK
/**
* @file
*
* Unless noted otherwise, the portions of Isis written by the USGS are public
* domain. See individual third-party library and package descriptions for
* intellectual property information,user agreements, and related information.
*
* Although Isis has been used by the USGS, no warranty, expressed or implied,
* is made by the USGS as to the accuracy and functioning of such software
* and related material nor shall the fact of distribution constitute any such
* warranty, and no responsibility is assumed by the USGS in connection
* therewith.
*
* For additional information, launch
* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see
* the Privacy &amp; Disclaimers page on the Isis website,
* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
* http://www.usgs.gov/privacy.html.
*/
#include <cmath>
#include <iomanip>
#include <iostream>
#include "Camera.h"
#include "CameraFactory.h"
#include "FileName.h"
#include "IException.h"
#include "Preference.h"
#include "Pvl.h"
using namespace std;
using namespace Isis;
void TestLineSamp(Camera *cam, double samp, double line);
/**
* @internal
*
* @history 2020-04-09 Stuart Sides - Original version.
*/
int main(void) {
Preference::Preferences(true);
cout << "Unit Test for MexHrscSrcCamera..." << endl;
try {
// These should be lat/lon at center of image. To obtain these numbers for a new cube/camera,
// set both the known lat and known lon to zero and copy the unit test output "Latitude off by: "
// and "Longitude off by: " values directly into these variables.
double knownLat = -9.3335948038633116;
double knownLon = 90.4734324741402531;
Cube c("$mex/testData/H0010_0023_SR2.cub", "r");
Camera *cam = CameraFactory::Create(c);
cout << "FileName: " << FileName(c.fileName()).name() << endl;
cout << "CK Frame: " << cam->instrumentRotation()->Frame() << endl << endl;
cout.setf(std::ios::fixed);
cout << setprecision(9);
// Test kernel IDs
cout << "Kernel IDs: " << endl;
cout << "CK Frame ID = " << cam->CkFrameId() << endl;
cout << "CK Reference ID = " << cam->CkReferenceId() << endl;
cout << "SPK Target ID = " << cam->SpkTargetId() << endl;
cout << "SPK Reference ID = " << cam->SpkReferenceId() << endl << endl;
// Test name methods
cout << "Spacecraft Name Long: " << cam->spacecraftNameLong() << endl;
cout << "Spacecraft Name Short: " << cam->spacecraftNameShort() << endl;
cout << "Instrument Name Long: " << cam->instrumentNameLong() << endl;
cout << "Instrument Name Short: " << cam->instrumentNameShort() << endl << endl;
// Test all four corners to make sure the conversions are right
cout << "For upper left corner ..." << endl;
TestLineSamp(cam, 1.0, 1.0);
cout << "For upper right corner ..." << endl;
TestLineSamp(cam, cam->Samples(), 1.0);
cout << "For lower left corner ..." << endl;
TestLineSamp(cam, 1.0, cam->Lines());
cout << "For lower right corner ..." << endl;
TestLineSamp(cam, cam->Samples(), cam->Lines());
double samp = cam->Samples() / 2.0;
double line = cam->Lines() / 2.0;
cout << "For center pixel position ..." << endl;
if (!cam->SetImage(samp, line)) {
cout << "ERROR" << endl;
return 0;
}
if (fabs(cam->UniversalLatitude() - knownLat) < 1.81E-5) {
cout << "Latitude OK" << endl;
}
else {
cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl;
}
if (fabs(cam->UniversalLongitude() - knownLon) < 1.4E-6) {
cout << "Longitude OK" << endl;
}
else {
cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl;
}
}
catch (IException &e) {
e.print();
}
}
void TestLineSamp(Camera *cam, double samp, double line) {
bool success = cam->SetImage(samp, line);
if (success) {
success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude());
}
if (success) {
double deltaSamp = samp - cam->Sample();
double deltaLine = line - cam->Line();
if (fabs(deltaSamp) < 0.008) deltaSamp = 0.0;
if (fabs(deltaLine) < 0.008) deltaLine = 0.0;
cout << "DeltaSample = " << deltaSamp << endl;
cout << "DeltaLine = " << deltaLine << endl << endl;
}
else {
cout << "DeltaSample = ERROR" << endl;
cout << "DeltaLine = ERROR" << endl << endl;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment