Skip to content

Commit

Permalink
Adds the ability to save and restore a greyscale stretch to/from a Cu…
Browse files Browse the repository at this point in the history
…be (#3717)

* Update meta.yaml to rename conda package to isis from isis3

* Initial stretch attempt

* Now will write a single stretch with a name and type to the cube

* Stretch updated to inherit from Blob, re-loading a saved stretch works but only if Linear right now

* Clean up Stretch class

* Completely move stretchTypes into stretch class, and some minor cleanup

* Fixed combo-box not updating bug and more cleanup

* Further cleanup of propagated earlier changes with types and names being removed from unnecessary classes

* Removed added unneeded member variables from StretchType

* Cleanup StretchTool class

* Update enter-text dialogs to drop down selection options

* Wrapped some long strings

* Initial commit to address most of review comments

* Removed buttons in case of RGB stretch and add a 'Color' PvlKeyword to Stretch output

Co-authored-by: Stuart Sides <[email protected]>
  • Loading branch information
krlberry and scsides authored Feb 28, 2020
1 parent 834b5b5 commit 3b955cd
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 19 deletions.
106 changes: 105 additions & 1 deletion isis/src/base/objs/Stretch/Stretch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Isis {
* Constructs a Stretch object with default mapping of special pixel values to
* themselves.
*/
Stretch::Stretch() {
Stretch::Stretch() : Blob("ImageStretch", "Stretch") {
p_null = Isis::NULL8;
p_lis = Isis::LOW_INSTR_SAT8;
p_lrs = Isis::LOW_REPR_SAT8;
Expand All @@ -47,8 +47,29 @@ namespace Isis {
p_minimum = p_lrs;
p_maximum = p_hrs;
p_pairs = 0;
p_type = "None";
}


/**
* Constructs a Stretch object with default mapping of special pixel values to
* themselves and a provided name.
*
* @param name Name to use for Stretch
*/
Stretch::Stretch(QString name) : Blob(name, "Stretch") {
p_null = Isis::NULL8;
p_lis = Isis::LOW_INSTR_SAT8;
p_lrs = Isis::LOW_REPR_SAT8;
p_his = Isis::HIGH_INSTR_SAT8;
p_hrs = Isis::HIGH_REPR_SAT8;
p_minimum = p_lrs;
p_maximum = p_hrs;
p_pairs = 0;
p_type = "None";
}


/**
* Adds a stretch pair to the list of pairs. Note that all input pairs must be
* in ascending order.
Expand Down Expand Up @@ -410,6 +431,89 @@ namespace Isis {
this->p_output = other.p_output;
}


/**
* Read saved Stretch data from a Cube into this object.
*
* This is called by Blob::Read() and is the actual data reading function
* ultimately called when running something like cube->read(stretch);
*
* @param is input stream containing the saved Stretch information
*/
void Stretch::ReadData(std::istream &is) {
// Set the Stretch Type
p_type = p_blobPvl["StretchType"][0];

// Read in the Stretch Pairs
streampos sbyte = p_startByte - 1;
is.seekg(sbyte, std::ios::beg);
if (!is.good()) {
QString msg = "Error preparing to read data from " + p_type +
" [" + p_blobName + "]";
throw IException(IException::Io, msg, _FILEINFO_);
}

char *buf = new char[p_nbytes+1];
memset(buf, 0, p_nbytes + 1);

is.read(buf, p_nbytes);

// Read buffer data into a QString so we can call Parse()
std::string stringFromBuffer(buf);
QString qStringFromBuffer = QString::fromStdString(stringFromBuffer);
Parse(qStringFromBuffer);

delete [] buf;

if (!is.good()) {
QString msg = "Error reading data from " + p_type + " [" +
p_blobName + "]";
throw IException(IException::Io, msg, _FILEINFO_);
}
}


/**
* Get the Type of Stretch. This is only used by the AdvancedStretchTool.
*
* @return QString Type of Stretch.
*/
QString Stretch::getType(){
return p_type;
}


/**
* Set the Type of Stretch. This is only used by the AdvancedStretchTool.
*
* @param stretchType The type of stretch.
*/
void Stretch::setType(QString stretchType){
// check to see if valid input
p_type = stretchType;
}


/**
* Initializes for writing stretch to cube blob
*/
void Stretch::WriteInit() {
p_nbytes = Text().toStdString().size();
}


/**
* Writes the stretch information to a cube.
*
* This is called by Blob::write() and is ultimately the function
* called when running something like cube->write(stretch);
*
* @param os output stream to write the stretch data to.
*/
void Stretch::WriteData(std::fstream &os) {
os.write(Text().toStdString().c_str(), p_nbytes);
}

} // end namespace isis


17 changes: 15 additions & 2 deletions isis/src/base/objs/Stretch/Stretch.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <string>
#include "Pvl.h"
#include "Histogram.h"
#include "Blob.h"

namespace Isis {
/**
Expand Down Expand Up @@ -67,9 +68,10 @@ namespace Isis {
* Created second Parse method for handling pairs where the
* input side is a perentage. Fixed Input and Output getters
* to check both sides of boundry condition for valid data
*
* @history 2020-02-27 Kristin Berry - Updated to inherit from Blob so Stretches can be
* saved and restored from cubes.
*/
class Stretch {
class Stretch : public Isis::Blob {
private:
std::vector<double> p_input; //!< Array for input side of stretch pairs
std::vector<double> p_output; //!< Array for output side of stretch pairs
Expand All @@ -88,10 +90,13 @@ namespace Isis {
double p_minimum; //!<By default this value is set to p_lrs
double p_maximum; //!<By default this value is set to p_hrs

QString p_type; //! Type of stretch. This is only currently used in the AdvancedStretchTool.

std::pair<double, double> NextPair(QString &pairs);

public:
Stretch();
Stretch(QString name);

//! Destroys the Stretch object
~Stretch() {};
Expand Down Expand Up @@ -177,6 +182,9 @@ namespace Isis {
return p_pairs;
};

QString getType();
void setType(QString type);

double Input(const int index) const;
double Output(const int index) const;

Expand All @@ -188,6 +196,11 @@ namespace Isis {
};

void CopyPairs(const Stretch &other);

protected:
void WriteInit();
void ReadData(std::istream &is);
void WriteData(std::fstream &os);
};
};

Expand Down
61 changes: 53 additions & 8 deletions isis/src/qisis/objs/StretchTool/AdvancedStretch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QMessageBox>

#include "Stretch.h"
#include "IString.h"
Expand Down Expand Up @@ -35,40 +36,52 @@ namespace Isis {
typeSelectionArea->setLayout(new QHBoxLayout());
typeSelectionArea->layout()->addWidget(new QLabel("Stretch Type"));

QComboBox *stretchTypeSelection = new QComboBox();
stretchTypeSelection->addItem("Linear", 0);
stretchTypeSelection->addItem("Sawtooth", 1);
stretchTypeSelection->addItem("Binary", 2);
stretchTypeSelection->addItem("Manual", 3);
p_stretchTypeSelection = new QComboBox();
p_stretchTypeSelection->addItem("Linear", 0);
p_stretchTypeSelection->addItem("Sawtooth", 1);
p_stretchTypeSelection->addItem("Binary", 2);
p_stretchTypeSelection->addItem("Manual", 3);

typeSelectionArea->layout()->addWidget(stretchTypeSelection);
typeSelectionArea->layout()->addWidget(p_stretchTypeSelection);
layout()->addWidget(typeSelectionArea);

p_stretchTypeStack = new QStackedWidget();
LinearStretchType *linear = new LinearStretchType(hist, curStretch,
name, color);
connect(linear, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
connect(linear, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
connect(linear, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
connect(linear, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
p_stretchTypeStack->addWidget(linear);

SawtoothStretchType *sawtooth = new SawtoothStretchType(hist, curStretch,
name, color);
connect(sawtooth, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
connect(sawtooth, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
connect(sawtooth, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
connect(sawtooth, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
p_stretchTypeStack->addWidget(sawtooth);

BinaryStretchType *binary = new BinaryStretchType(hist, curStretch,
name, color);
connect(binary, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
connect(binary, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
connect(binary, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
connect(binary, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
p_stretchTypeStack->addWidget(binary);

ManualStretchType *manual = new ManualStretchType(hist, curStretch,
name, color);
connect(manual, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged()));
connect(manual, SIGNAL(saveToCube()), this, SIGNAL(saveToCube()));
connect(manual, SIGNAL(deleteFromCube()), this, SIGNAL(deleteFromCube()));
connect(manual, SIGNAL(loadStretch()), this, SIGNAL(loadStretch()));
p_stretchTypeStack->addWidget(manual);

layout()->addWidget(p_stretchTypeStack);
connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
connect(p_stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
p_stretchTypeStack, SLOT(setCurrentIndex(int)));
connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
connect(p_stretchTypeSelection, SIGNAL(currentIndexChanged(int)),
this, SIGNAL(stretchChanged()));
}

Expand Down Expand Up @@ -105,6 +118,38 @@ namespace Isis {
}


/**
* Used to restore a saved Stretch from a cube. This function is
* distinct from setStretch in that setStretch deliberately _does not_
* change the stretch type, and this function does change the stretch type.
*
* @param newStretch saved stretch to restore
*/
void AdvancedStretch::restoreSavedStretch(Stretch newStretch) {
QString stretchTypeName = newStretch.getType();

int index = 0;
if (stretchTypeName.compare("LinearStretch") == 0 ) {
index = 0;
}
else if (stretchTypeName.compare("SawtoothStretch") == 0 ) {
index = 1;
}
else if (stretchTypeName.compare("BinaryStretch") == 0) {
index = 2;
}
else if (stretchTypeName.compare("ManualStretch") == 0) {
index = 3;
}
// Fail by defaulting to Linear

p_stretchTypeSelection->setCurrentIndex(index);
StretchType *stretchType = (StretchType *)
p_stretchTypeStack->currentWidget();
stretchType->setStretch(newStretch);
}


/**
* This is called when the visible area changes, so that the
* histogram can be updated. It is essential that the stretch
Expand Down
8 changes: 6 additions & 2 deletions isis/src/qisis/objs/StretchTool/AdvancedStretch.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QWidget>

class QStackedWidget;
class QComboBox;
class QLayout;
class QString;
class QColor;
Expand Down Expand Up @@ -36,16 +37,19 @@ namespace Isis {
~AdvancedStretch();
Stretch getStretch();
void setStretch(Stretch newStretch);
void restoreSavedStretch(Stretch newStretch);
void setHistogram(const Histogram &newHist);

signals:
//! Emitted when a new stretch is available
void stretchChanged();

protected:
void saveToCube();
void deleteFromCube();
void loadStretch();

private:
QStackedWidget *p_stretchTypeStack; //!< StretchType's
QComboBox *p_stretchTypeSelection; //!< ComboBox of StretchTypes
};
};

Expand Down
21 changes: 20 additions & 1 deletion isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ namespace Isis {
p_bluStretch = NULL;
p_enabled = false;

setWindowTitle("Advanced Stretch Tool");

QHBoxLayout *layout = new QHBoxLayout();

setLayout(layout);
}

Expand Down Expand Up @@ -124,6 +127,22 @@ namespace Isis {

connect(p_grayStretch, SIGNAL(stretchChanged()),
this, SIGNAL(stretchChanged()));
connect(p_grayStretch, SIGNAL(saveToCube()),
this, SIGNAL(saveToCube()));
connect(p_grayStretch, SIGNAL(deleteFromCube()),
this, SIGNAL(deleteFromCube()));
connect(p_grayStretch, SIGNAL(loadStretch()),
this, SIGNAL(loadStretch()));
}


/**
* Restores a saved stretch from the cube
*
* @param stretch
*/
void AdvancedStretchDialog::restoreSavedStretch(Stretch stretch){
p_grayStretch->restoreSavedStretch(stretch);
}


Expand Down Expand Up @@ -213,7 +232,7 @@ namespace Isis {


/**
* This calls setHistogram on the gray advanced stretche. This
* This calls setHistogram on the gray advanced stretches. This
* should be called every time the visible area changes.
*
* @param grayHist Histogram of visible area on gray band
Expand Down
4 changes: 4 additions & 0 deletions isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace Isis {
Histogram &grayHist);
void updateHistogram(const Histogram &grayHist);
bool isRgbMode() const;
void restoreSavedStretch(Stretch stretch);

Stretch getGrayStretch();
Stretch getRedStretch();
Expand Down Expand Up @@ -77,6 +78,9 @@ namespace Isis {
void stretchChanged();
//! Emitted when this dialog is shown or hidden
void visibilityChanged();
void saveToCube();
void deleteFromCube();
void loadStretch();

public slots:
void updateStretch(CubeViewport *);
Expand Down
2 changes: 2 additions & 0 deletions isis/src/qisis/objs/StretchTool/BinaryStretchType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ namespace Isis {
sliderWidget->setLayout(sliderLayout);
p_mainLayout->addWidget(sliderWidget, 1, 0);

p_stretch->setType("BinaryStretch");

setLayout(p_mainLayout);
setStretch(calculateNewStretch());
}
Expand Down
Loading

0 comments on commit 3b955cd

Please sign in to comment.