|
Isis 3.0 Object Programmers' Reference |
Home |
00001 00022 #include <iostream> 00023 #include <iomanip> 00024 #include "ProcessExport.h" 00025 #include "Preference.h" 00026 #include "IException.h" 00027 #include "LineManager.h" 00028 #include "BandManager.h" 00029 #include "SpecialPixel.h" 00030 #include "Histogram.h" 00031 #include "Stretch.h" 00032 #include "Application.h" 00033 #include "EndianSwapper.h" 00034 #include "Projection.h" 00035 00036 using namespace std; 00037 namespace Isis { 00038 00040 ProcessExport::ProcessExport() : Isis::Process() { 00041 00042 p_outputMinimum = 0.0; 00043 p_outputMiddle = 0.5; 00044 p_outputMaximum = 1.0; 00045 00046 p_inputMinimum.clear(); 00047 p_inputMiddle.clear(); 00048 p_inputMaximum.clear(); 00049 00050 p_endianSwap = NULL; 00051 00052 SetFormat(BSQ); 00053 SetOutputEndian(Isis::IsLsb() ? Isis::Lsb : Isis::Msb); 00054 SetOutputType(Isis::Real); 00055 00056 p_Null_Set = false; 00057 p_Lis_Set = false; 00058 p_Lrs_Set = false; 00059 p_His_Set = false; 00060 p_Hrs_Set = false; 00061 00062 p_progress->SetText("Exporting"); 00063 } 00064 00065 00067 ProcessExport::~ProcessExport() { 00068 if(p_endianSwap != NULL) { 00069 delete p_endianSwap; 00070 } 00071 for(unsigned int i = 0; i < p_str.size(); i++) { 00072 delete p_str[i]; 00073 } 00074 p_str.clear(); 00075 } 00076 00077 00100 void ProcessExport::SetInputRange(const double minimum, const double maximum) { 00101 double middle = (minimum + maximum) / 2.0; 00102 SetInputRange(minimum, middle, maximum); 00103 } 00104 00129 void ProcessExport::SetInputRange(const double minimum, const double maximum, const int index) { 00130 double middle = (minimum + maximum) / 2.0; 00131 SetInputRange(minimum, middle, maximum, index); 00132 } 00133 00160 void ProcessExport::SetInputRange(const double minimum, const double middle, 00161 const double maximum) { 00162 if(minimum >= middle) { 00163 string message = 00164 "minimum must be less than the middle [ProcessExport::SetInputRange]"; 00165 throw IException(IException::Programmer, message, _FILEINFO_); 00166 } 00167 if(middle >= maximum) { 00168 string message = 00169 "middle must be less than the maximum [ProcessExport::SetInputRange]"; 00170 throw IException(IException::Programmer, message, _FILEINFO_); 00171 } 00172 p_inputMinimum.clear(); 00173 p_inputMinimum.resize(InputCubes.size(), minimum); 00174 p_inputMiddle.clear(); 00175 p_inputMiddle.resize(InputCubes.size(), middle); 00176 p_inputMaximum.clear(); 00177 p_inputMaximum.resize(InputCubes.size(), maximum); 00178 } 00179 00208 void ProcessExport::SetInputRange(const double minimum, const double middle, 00209 const double maximum, const int index) { 00210 if(minimum >= middle) { 00211 string message = 00212 "minimum must be less than the middle [ProcessExport::SetInputRange]"; 00213 throw IException(IException::Programmer, message, _FILEINFO_); 00214 } 00215 if(middle >= maximum) { 00216 string message = 00217 "middle must be less than the maximum [ProcessExport::SetInputRange]"; 00218 throw IException(IException::Programmer, message, _FILEINFO_); 00219 } 00220 if(index >= (int)InputCubes.size() || index < 0) { 00221 string message = 00222 "index out of bounds"; 00223 throw IException(IException::Programmer, message, _FILEINFO_); 00224 } 00225 00226 p_inputMinimum.resize(index + 1, minimum); 00227 p_inputMiddle.resize(index + 1, middle); 00228 p_inputMaximum.resize(index + 1, maximum); 00229 p_inputMinimum[index] = minimum; 00230 p_inputMiddle[index] = middle; 00231 p_inputMaximum[index] = maximum; 00232 } 00233 00366 void ProcessExport::SetInputRange() { 00367 p_inputMinimum.clear(); 00368 p_inputMiddle.clear(); 00369 p_inputMaximum.clear(); 00370 00371 for(unsigned int i = 0; i < InputCubes.size(); i++) { 00372 // Get the manual stretch parameters if needed 00373 QString strType = Application::GetUserInterface().GetString("STRETCH"); 00374 if(strType == "MANUAL") { 00375 p_inputMinimum.push_back(Application::GetUserInterface().GetDouble("MINIMUM")); 00376 p_inputMaximum.push_back(Application::GetUserInterface().GetDouble("MAXIMUM")); 00377 00378 p_inputMiddle.push_back(Isis::NULL8); 00379 } 00380 00381 // Or get the automatic parameters 00382 else if(strType != "NONE") { 00383 Isis::Histogram *hist = InputCubes[i]->histogram(0); 00384 p_inputMinimum.push_back(hist->Percent( 00385 Application::GetUserInterface().GetDouble("MINPERCENT"))); 00386 p_inputMaximum.push_back(hist->Percent( 00387 Application::GetUserInterface().GetDouble("MAXPERCENT"))); 00388 p_inputMiddle.push_back(Isis::NULL8); 00389 Application::GetUserInterface().Clear("MINIMUM"); 00390 Application::GetUserInterface().Clear("MAXIMUM"); 00391 Application::GetUserInterface().PutDouble("MINIMUM", p_inputMinimum[i]); 00392 Application::GetUserInterface().PutDouble("MAXIMUM", p_inputMaximum[i]); 00393 00394 if(strType == "PIECEWISE") { 00395 p_inputMiddle[i] = hist->Median(); 00396 00397 // If the median is the min or max, back off to linear 00398 if(p_inputMiddle[i] == p_inputMinimum[i] || 00399 p_inputMiddle[i] == p_inputMaximum[i]) { 00400 p_inputMiddle[i] = Isis::NULL8; 00401 } 00402 } 00403 00404 // Make sure the image isn't constant 00405 if(p_inputMinimum[i] == p_inputMaximum[i]) { 00406 p_inputMaximum[i] = p_inputMinimum[i] + 1.0; 00407 if(strType == "PIECEWISE") p_inputMiddle[i] = p_inputMinimum[i] + 0.5; 00408 } 00409 } 00410 } 00411 } 00412 00413 00414 bool ProcessExport::HasInputRange() const { 00415 return p_inputMinimum.size() > 0; 00416 } 00417 00418 00420 double ProcessExport::GetInputMinimum(unsigned int n) const { 00421 if (n >= p_inputMinimum.size()) 00422 throw IException(IException::Programmer, 00423 "There is no input minimum for channel " + IString((int) n), 00424 _FILEINFO_); 00425 00426 return p_inputMinimum[n]; 00427 } 00428 00429 00431 double ProcessExport::GetInputMaximum(unsigned int n) const { 00432 if (n >= p_inputMaximum.size()) 00433 throw IException(IException::Programmer, 00434 "There is no input maximum for channel " + IString((int) n), 00435 _FILEINFO_); 00436 00437 return p_inputMaximum[n]; 00438 } 00439 00440 00456 void ProcessExport::SetOutputRange(const double minimum, const double maximum) { 00457 if(minimum >= maximum) { 00458 string message = 00459 "minimum must be less than the maximum [ProcessExport::SetOutputRange]"; 00460 throw IException(IException::Programmer, message, _FILEINFO_); 00461 } 00462 00463 p_outputMinimum = minimum; 00464 p_outputMaximum = maximum; 00465 p_outputMiddle = (p_outputMinimum + p_outputMaximum) / 2.0; 00466 } 00467 00468 00478 void ProcessExport::SetOutputNull(const double value) { 00479 p_Null = value; 00480 p_Null_Set = true; 00481 } 00482 00483 00493 void ProcessExport::SetOutputLis(const double value) { 00494 p_Lis = value; 00495 p_Lis_Set = true; 00496 } 00497 00498 00508 void ProcessExport::SetOutputLrs(const double value) { 00509 p_Lrs = value; 00510 p_Lrs_Set = true; 00511 } 00512 00513 00523 void ProcessExport::SetOutputHis(const double value) { 00524 p_His = value; 00525 p_His_Set = true; 00526 } 00527 00528 00538 void ProcessExport::SetOutputHrs(const double value) { 00539 p_Hrs = value; 00540 p_Hrs_Set = true; 00541 } 00542 00543 00547 double ProcessExport::OutputNull() { 00548 return p_Null_Set ? p_Null : p_outputMinimum; 00549 } 00550 00551 00555 double ProcessExport::OutputLis() { 00556 return p_Lis_Set ? p_Lis : p_outputMinimum; 00557 } 00558 00559 00563 double ProcessExport::OutputLrs() { 00564 return p_Lrs_Set ? p_Lrs : p_outputMinimum; 00565 } 00566 00567 00571 double ProcessExport::OutputHis() { 00572 return p_His_Set ? p_His : p_outputMaximum; 00573 } 00574 00575 00579 double ProcessExport::OutputHrs() { 00580 return p_Hrs_Set ? p_Hrs : p_outputMaximum; 00581 } 00582 00583 00610 void ProcessExport::SetOutputType(Isis::PixelType pixelIn) { 00611 p_pixelType = pixelIn; 00612 00613 if(p_format < 0 || p_format > 3) { 00614 string message = 00615 "Format of the output file must be set prior to calling this method [ProcessExport::SetOutputType]"; 00616 throw IException(IException::Programmer, message, _FILEINFO_); 00617 } 00618 if(pixelIn == Isis::UnsignedByte) 00619 SetOutputRange((double)VALID_MIN1, (double)VALID_MAX1); 00620 else if(pixelIn == Isis::UnsignedWord) 00621 SetOutputRange((double)VALID_MINU2, (double)VALID_MAXU2); 00622 else if(pixelIn == Isis::SignedWord) 00623 SetOutputRange((double)VALID_MIN2, (double)VALID_MAX2); 00624 else if(pixelIn == Isis::Real) 00625 if(p_format == JP2) { 00626 string message = 00627 "Unsupported bit type for JP2 formatted files [ProcessExport::SetOutputType]"; 00628 throw IException(IException::Programmer, message, _FILEINFO_); 00629 } 00630 else { 00631 SetOutputRange(-DBL_MAX, DBL_MAX); 00632 } 00633 else { 00634 string message = 00635 "Unsupported bit type [ProcessExport::SetOutputType]"; 00636 throw IException(IException::Programmer, message, _FILEINFO_); 00637 } 00638 } 00639 00640 00651 void ProcessExport::SetOutputEndian(enum ByteOrder byteOrderIn) { 00652 if(p_endianSwap != NULL) { 00653 delete p_endianSwap; 00654 } 00655 p_endianType = byteOrderIn; 00656 if(byteOrderIn == Isis::NoByteOrder) { 00657 p_endianSwap = new EndianSwapper("NoByteOrder"); 00658 } 00659 else if(byteOrderIn == Isis::Lsb) { 00660 p_endianSwap = new EndianSwapper("LSB"); 00661 } 00662 else if(byteOrderIn == Isis::Msb) { 00663 p_endianSwap = new EndianSwapper("MSB"); 00664 } 00665 } 00666 00667 00678 void ProcessExport::InitProcess() { 00679 if(InputCubes.size() < 1) { 00680 string m = "You have not specified any input cubes"; 00681 throw IException(IException::Programmer, m, _FILEINFO_); 00682 } 00683 00684 // TODO this really belongs here, but causes problems because of its 00685 // coupling with an application User Interface that contains a STRETCH 00686 // parameter 00687 //if (!HasInputRange()) SetInputRange(); 00688 00689 // Construct a line buffer manager 00690 if(p_format == BIP) { 00691 p_progress->SetMaximumSteps((InputCubes[0]->sampleCount()) * (InputCubes[0]->lineCount())); 00692 } 00693 else { 00694 p_progress->SetMaximumSteps((InputCubes[0]->lineCount()) * (InputCubes[0]->bandCount())); 00695 } 00696 00697 00698 // Setup a stretch object 00699 p_str.clear(); 00700 for(unsigned int i = 0; i < InputCubes.size(); i++) { 00701 p_str.push_back(new Stretch()); 00702 if(p_inputMinimum.size() > 0) { 00703 if(Isis::IsValidPixel(p_inputMinimum[i])) { 00704 p_str[i]->AddPair(p_inputMinimum[i], p_outputMinimum); 00705 if(Isis::IsValidPixel(p_inputMiddle[i])) { 00706 p_str[i]->AddPair(p_inputMiddle[i], p_outputMiddle); 00707 } 00708 p_str[i]->AddPair(p_inputMaximum[i], p_outputMaximum); 00709 } 00710 } 00711 00712 p_str[i]->SetNull(p_Null_Set ? p_Null : p_outputMinimum); 00713 p_str[i]->SetLis(p_Lis_Set ? p_Lis : p_outputMinimum); 00714 p_str[i]->SetLrs(p_Lrs_Set ? p_Lrs : p_outputMinimum); 00715 p_str[i]->SetHis(p_His_Set ? p_His : p_outputMaximum); 00716 p_str[i]->SetHrs(p_Hrs_Set ? p_Hrs : p_outputMaximum); 00717 } 00718 00719 p_progress->CheckStatus(); 00720 return; 00721 } 00722 00723 00742 void ProcessExport::StartProcess(void funct(Isis::Buffer &in)) { 00743 InitProcess(); 00744 00745 Isis::BufferManager *buff; 00746 if(p_format == BSQ) { 00747 buff = new Isis::LineManager(*InputCubes[0]); 00748 } 00749 else if(p_format == BIL || p_format == JP2) { 00750 buff = new Isis::LineManager(*InputCubes[0], true); 00751 } 00752 else if(p_format == BIP) { 00753 buff = new Isis::BandManager(*InputCubes[0]); 00754 } 00755 else { 00756 string m = "Invalid storage order."; 00757 throw IException(IException::Programmer, m, _FILEINFO_); 00758 } 00759 00760 // Loop and let the app programmer fiddle with the buffers 00761 for(buff->begin(); !buff->end(); buff->next()) { 00762 // Read a line of data 00763 InputCubes[0]->read(*buff); 00764 // Stretch the pixels into the desired range 00765 for(int i = 0; i < buff->size(); i++) { 00766 (*buff)[i] = p_str[0]->Map((*buff)[i]); 00767 } 00768 // Invoke the user function 00769 funct(*buff); 00770 p_progress->CheckStatus(); 00771 } 00772 } 00773 00774 00793 void ProcessExport::StartProcess(void funct(vector<Buffer *> &in)) { 00794 int length = (p_format == BIP) ? 00795 InputCubes[0]->bandCount() : InputCubes[0]->lineCount(); 00796 00797 // Loop and let the app programmer fiddle with the lines 00798 vector<BufferManager *> imgrs = GetBuffers(); 00799 for (int k = 1; k <= length; k++) { 00800 vector<Buffer *> ibufs; 00801 00802 for (unsigned int j = 0; j < InputCubes.size(); j++) { 00803 // Read a line of data 00804 InputCubes[j]->read(*imgrs[j]); 00805 00806 // Stretch the pixels into the desired range 00807 for (int i = 0; i < InputCubes[0]->sampleCount(); i++) 00808 (*imgrs[j])[i] = p_str[j]->Map((*imgrs[j])[i]); 00809 00810 ibufs.push_back(imgrs[j]); 00811 } 00812 00813 // Invoke the user function 00814 funct(ibufs); 00815 00816 for (unsigned int i = 0; i < imgrs.size(); i++) imgrs[i]->next(); 00817 p_progress->CheckStatus(); 00818 } 00819 } 00820 00821 00822 vector<BufferManager *> ProcessExport::GetBuffers() { 00823 InitProcess(); 00824 vector<BufferManager *> imgrs; 00825 if (p_format == BSQ) { 00826 imgrs = GetBuffersBSQ(); 00827 } 00828 else if (p_format == BIL || p_format == JP2) { 00829 imgrs = GetBuffersBIL(); 00830 } 00831 else if (p_format == BIP) { 00832 imgrs = GetBuffersBIP(); 00833 } 00834 else { 00835 string m = "Invalid storage order."; 00836 throw IException(IException::Programmer, m, _FILEINFO_); 00837 } 00838 return imgrs; 00839 } 00840 00841 00857 vector<BufferManager *> ProcessExport::GetBuffersBSQ() { 00858 int samples = InputCubes[0]->sampleCount(); 00859 int lines = InputCubes[0]->lineCount(); 00860 00861 vector<BufferManager *> imgrs; 00862 for (unsigned int i = 0; i < InputCubes.size(); i++) { 00863 if((InputCubes[i]->sampleCount() == samples) && 00864 (InputCubes[i]->lineCount() == lines)) { 00865 00866 Isis::LineManager *iline = new Isis::LineManager(*InputCubes[i]); 00867 iline->begin(); 00868 imgrs.push_back(iline); 00869 } 00870 else { 00871 string m = "All input cubes must have the same dimensions"; 00872 throw IException(IException::Programmer, m, _FILEINFO_); 00873 } 00874 } 00875 00876 return imgrs; 00877 } 00878 00879 00896 vector<BufferManager *> ProcessExport::GetBuffersBIL() { 00897 int samples = InputCubes[0]->sampleCount(); 00898 int lines = InputCubes[0]->lineCount(); 00899 00900 vector<BufferManager *> imgrs; 00901 for (unsigned int i = 0; i < InputCubes.size(); i++) { 00902 if ((InputCubes[i]->sampleCount() == samples) && 00903 (InputCubes[i]->lineCount() == lines)) { 00904 00905 Isis::LineManager *iline = new Isis::LineManager(*InputCubes[i], true); 00906 iline->begin(); 00907 imgrs.push_back(iline); 00908 } 00909 else { 00910 string m = "All input cubes must have the same dimensions"; 00911 throw IException(IException::Programmer, m, _FILEINFO_); 00912 } 00913 } 00914 00915 return imgrs; 00916 } 00917 00934 vector<BufferManager *> ProcessExport::GetBuffersBIP() { 00935 int bands = InputCubes[0]->bandCount(); 00936 int samples = InputCubes[0]->sampleCount(); 00937 00938 vector<BufferManager *> imgrs; 00939 for(unsigned int i = 0; i < InputCubes.size(); i++) { 00940 if((InputCubes[i]->bandCount() == bands) && (InputCubes[i]->sampleCount() == samples)) { 00941 Isis::BandManager *iband = new Isis::BandManager(*InputCubes[i]); 00942 iband->begin(); 00943 imgrs.push_back(iband); 00944 } 00945 else { 00946 string m = "All input cubes must have the same dimensions"; 00947 throw IException(IException::Programmer, m, _FILEINFO_); 00948 } 00949 } 00950 00951 return imgrs; 00952 } 00953 00954 00955 00956 00969 void ProcessExport::StartProcess(std::ofstream &fout) { 00970 InitProcess(); 00971 00972 Isis::BufferManager *buff; 00973 if(p_format == BSQ) { 00974 buff = new Isis::LineManager(*InputCubes[0]); 00975 } 00976 else if(p_format == BIL) { 00977 buff = new Isis::LineManager(*InputCubes[0], true); 00978 } 00979 else if(p_format == BIP) { 00980 buff = new Isis::BandManager(*InputCubes[0]); 00981 } 00982 else { 00983 string m = "Output stream cannot be generated for requested storage order type."; 00984 throw IException(IException::Programmer, m, _FILEINFO_); 00985 } 00986 00987 // Loop for each line of data 00988 for(buff->begin(); !buff->end(); buff->next()) { 00989 // Read a line of data 00990 InputCubes[0]->read(*buff); 00991 // Stretch the pixels into the desired range 00992 for(int i = 0; i < buff->size(); i++) { 00993 (*buff)[i] = p_str[0]->Map((*buff)[i]); 00994 } 00995 if(p_pixelType == Isis::UnsignedByte) 00996 isisOut8(*buff, fout); 00997 else if(p_pixelType == Isis::UnsignedWord) 00998 isisOut16u(*buff, fout); 00999 else if(p_pixelType == Isis::SignedWord) 01000 isisOut16s(*buff, fout); 01001 else if(p_pixelType == Isis::Real) 01002 isisOut32(*buff, fout); 01003 p_progress->CheckStatus(); 01004 } 01005 delete buff; 01006 return; 01007 } 01008 01009 01026 void ProcessExport::isisOut8(Buffer &in, std::ofstream &fout) { 01027 char *out8 = new char[in.size()]; 01028 for(int samp = 0; samp < in.size(); samp++) { 01029 double pixel = in[samp]; 01030 if(pixel <= 0.0) { 01031 out8[samp] = 0; 01032 } 01033 else if(pixel >= 255.0) { 01034 out8[samp] = 255; 01035 } 01036 else { 01037 out8[samp] = (char)(in[samp] + 0.5); //Rounds 01038 } 01039 } 01040 fout.write(out8, in.size()); 01041 delete[] out8; 01042 return; 01043 } 01044 01045 01063 void ProcessExport::isisOut16s(Buffer &in, std::ofstream &fout) { 01064 short *out16s = new short[in.size()]; 01065 for(int samp = 0; samp < in.size(); samp++) { 01066 double pixel = in[samp]; 01067 short tempShort; 01068 if(pixel <= -32768.0) { 01069 tempShort = -(short)32768; 01070 } 01071 else if(pixel >= 32767.0) { 01072 tempShort = (short)32767; 01073 } 01074 else { 01075 //Rounds 01076 if(in[samp] < 0.0) { 01077 tempShort = (short)(in[samp] - 0.5); 01078 } 01079 else { 01080 tempShort = (short)(in[samp] + 0.5); 01081 } 01082 } 01083 void *p_swap = &tempShort; 01084 out16s[samp] = p_endianSwap->ShortInt(p_swap); 01085 } 01086 fout.write((char *)out16s, in.size() * 2); 01087 delete[] out16s; 01088 return; 01089 } 01090 01091 01109 void ProcessExport::isisOut16u(Buffer &in, std::ofstream &fout) { 01110 unsigned short *out16u = new unsigned short[in.size()]; 01111 for(int samp = 0; samp < in.size(); samp++) { 01112 double pixel = in[samp]; 01113 unsigned short tempShort; 01114 if(pixel <= 0.0) { 01115 tempShort = 0; 01116 } 01117 else if(pixel >= 65535.0) { 01118 tempShort = 65535; 01119 } 01120 else { 01121 tempShort = (unsigned short)(in[samp] + 0.5); //Rounds 01122 } 01123 unsigned short *p_swap = &tempShort; 01124 out16u[samp] = p_endianSwap->UnsignedShortInt(p_swap); 01125 } 01126 01127 fout.write((char *)out16u, in.size() * 2); 01128 delete[] out16u; 01129 return; 01130 } 01131 01132 01149 void ProcessExport::isisOut32(Buffer &in, std::ofstream &fout) { 01150 int *out32 = new int[in.size()]; 01151 for(int samp = 0; samp < in.size(); samp++) { 01152 double pixel = in[samp]; 01153 float tempFloat; 01154 if(pixel <= -((double)FLT_MAX)) { 01155 tempFloat = -((double)FLT_MAX); 01156 } 01157 else if(pixel >= (double)FLT_MAX) { 01158 tempFloat = (double)FLT_MAX; 01159 } 01160 else { 01161 tempFloat = (double)in[samp]; 01162 } 01163 void *p_swap = &tempFloat; 01164 out32[samp] = p_endianSwap->ExportFloat(p_swap); 01165 } 01166 fout.write((char *)out32, in.size() * 4); 01167 delete[] out32; 01168 return; 01169 } 01170 01171 01182 void ProcessExport::CreateWorldFile(const QString &worldFile) { 01183 try { 01184 Projection *proj = InputCubes[0]->projection(); 01185 proj->SetWorld(1.0, 1.0); 01186 ofstream os; 01187 os.open(worldFile.toAscii().data(), ios::out); 01188 01189 // X resolution 01190 os << std::fixed << setprecision(15) 01191 << proj->Resolution() << endl; 01192 // scale and rotation 01193 os << 0.0 << endl; 01194 os << 0.0 << endl; 01195 01196 // Y resolution 01197 os << std::fixed << setprecision(15) 01198 << -proj->Resolution() << endl; 01199 01200 // Upper left x at pixel middle 01201 os << std::fixed << setprecision(15) 01202 << proj->XCoord() << endl; 01203 01204 // Upper left y at pixel middle 01205 os << std::fixed << setprecision(15) 01206 << proj->YCoord() << endl; 01207 01208 os.close(); 01209 } 01210 catch(IException &e) { 01211 } 01212 } 01213 }