14#include "BasisFunction.h"
15#include "BoxcarCachingAlgorithm.h"
17#include "Interpolator.h"
18#include "LeastSquares.h"
20#include "ProcessRubberSheet.h"
21#include "TileManager.h"
23#include "UniqueIOCachingAlgorithm.h"
37 p_bandChangeFunct = NULL;
42 p_startQuadSize = startSize;
43 p_endQuadSize = endSize;
46 m_patchStartSample = 1;
50 m_patchSampleIncrement = 4;
51 m_patchLineIncrement = 4;
103 int samples,
int lines,
104 int sampleIncrement,
int lineIncrement) {
106 m_patchStartSample = startSample;
107 m_patchStartLine = startLine;
108 m_patchSamples = samples;
109 m_patchLines = lines;
110 m_patchSampleIncrement = sampleIncrement;
111 m_patchLineIncrement = lineIncrement;
137 string m =
"You must specify exactly one input cube";
141 string m =
"You must specify exactly one output cube";
146 p_lineMap.resize(p_startQuadSize);
147 p_sampMap.resize(p_startQuadSize);
149 for (
unsigned int pos = 0; pos < p_lineMap.size(); pos++) {
150 p_lineMap[pos].resize(p_startQuadSize);
151 p_sampMap[pos].resize(p_startQuadSize);
158 Portal iportal(interp.Samples(), interp.Lines(),
160 interp.HotSample(), interp.HotLine());
166 if (p_bandChangeFunct == NULL) {
172 long long int tilesPerBand = otile.Tiles() /
OutputCubes[0]->bandCount();
174 for (
long long int tile = 1; tile <= tilesPerBand; tile++) {
175 bool useLastTileMap =
false;
176 for (
int band = 1; band <=
OutputCubes[0]->bandCount(); band++) {
177 otile.SetTile(tile, band);
180 if (p_startQuadSize <= 2 || min(
OutputCubes[0]->lineCount(),
OutputCubes[0]->sampleCount()) <= p_startQuadSize) {
181 SlowGeom(otile, iportal, trans, interp);
184 QuadTree(otile, iportal, trans, interp, useLastTileMap);
187 useLastTileMap =
true;
195 int lastOutputBand = -1;
197 for (otile.begin(); !otile.end(); otile++) {
199 if (lastOutputBand != otile.Band()) {
200 lastOutputBand = otile.Band();
202 p_bandChangeFunct(lastOutputBand);
205 if (p_startQuadSize <= 2) {
206 SlowGeom(otile, iportal, trans, interp);
209 QuadTree(otile, iportal, trans, interp,
false);
234 p_bandChangeFunct = funct;
241 double outputSamp, outputLine;
242 double inputSamp, inputLine;
243 int outputBand = otile.Band();
245 for (
int i = 0; i < otile.size(); i++) {
246 outputSamp = otile.Sample(i);
247 outputLine = otile.Line(i);
250 if (trans.Xform(inputSamp, inputLine, outputSamp, outputLine)) {
251 if ((inputSamp < 0.5) || (inputLine < 0.5) ||
252 (inputLine >
InputCubes[0]->lineCount() + 0.5) ||
253 (inputSamp >
InputCubes[0]->sampleCount() + 0.5)) {
258 iportal.SetPosition(inputSamp, inputLine, outputBand);
260 otile[i] = interp.Interpolate(inputSamp, inputLine,
261 iportal.DoubleBuffer());
271 void ProcessRubberSheet::QuadTree(TileManager &otile, Portal &iportal,
272 Transform &trans, Interpolator &interp,
273 bool useLastTileMap) {
276 vector<Quad *> quadTree;
278 if (!useLastTileMap) {
280 Quad *quad =
new Quad;
281 quad->sline = otile.Line();
282 quad->ssamp = otile.Sample();
284 quad->eline = otile.Line(otile.size() - 1);
285 quad->esamp = otile.Sample(otile.size() - 1);
286 quad->slineTile = otile.Line();
287 quad->ssampTile = otile.Sample();
289 quadTree.push_back(quad);
293 while (quadTree.size() > 0) {
294 ProcessQuad(quadTree, trans, p_lineMap, p_sampMap);
299 int outputBand = otile.Band();
300 for (
int i = 0, line = 0; line < p_startQuadSize; line++) {
301 for (
int samp = 0; samp < p_startQuadSize; samp++, i++) {
302 double inputLine = p_lineMap[line][samp];
303 double inputSamp = p_sampMap[line][samp];
304 if (inputLine != NULL8) {
305 iportal.SetPosition(inputSamp, inputLine, outputBand);
307 otile[i] = interp.Interpolate(inputSamp, inputLine,
308 iportal.DoubleBuffer());
331 int sline,
int eline,
int increment) {
333 for (
int line = sline; line <= eline; line += increment) {
334 for (
int sample = ssamp; sample <= esamp; sample += increment) {
338 if (trans.Xform(sjunk, ljunk, sample, line)) {
349 void ProcessRubberSheet::ProcessQuad(std::vector<Quad *> &quadTree,
351 std::vector< std::vector<double> > &lineMap,
352 std::vector< std::vector<double> > &sampMap) {
354 Quad *quad = quadTree[0];
355 double oline[4], osamp[4];
356 double iline[4], isamp[4];
360 oline[0] = quad->sline;
361 osamp[0] = quad->ssamp;
362 if (!trans.Xform(isamp[0], iline[0], osamp[0], oline[0])) {
367 oline[1] = quad->sline;
368 osamp[1] = quad->esamp;
369 if (!trans.Xform(isamp[1], iline[1], osamp[1], oline[1])) {
374 oline[2] = quad->eline;
375 osamp[2] = quad->ssamp;
376 if (!trans.Xform(isamp[2], iline[2], osamp[2], oline[2])) {
381 oline[3] = quad->eline;
382 osamp[3] = quad->esamp;
383 if (!trans.Xform(isamp[3], iline[3], osamp[3], oline[3])) {
390 if (badCorner == 4) {
391 if ((quad->eline - quad->sline) < p_endQuadSize) {
392 SlowQuad(quadTree, trans, lineMap, sampMap);
395 if (p_forceSamp !=
Null && p_forceLine !=
Null) {
396 if (p_forceSamp >= quad->ssamp && p_forceSamp <= quad->esamp &&
397 p_forceLine >= quad->sline && p_forceLine <= quad->eline) {
403 int centerSample = (quad->ssamp + quad->esamp) / 2;
404 int centerLine = (quad->sline + quad->eline) / 2;
421 if (
TestLine(trans, quad->ssamp + 1, quad->esamp - 1,
422 quad->sline, quad->sline, 4) ||
424 TestLine(trans, quad->ssamp + 1, quad->esamp - 1,
425 quad->eline, quad->eline, 4) ||
427 TestLine(trans, quad->ssamp, quad->ssamp,
428 quad->sline + 1, quad->eline - 1, 4) ||
430 TestLine(trans, quad->esamp, quad->esamp,
431 quad->sline + 1, quad->eline - 1, 4) ||
433 TestLine(trans, centerSample, centerSample,
434 quad->sline + 1, quad->eline - 1, 4) ||
436 TestLine(trans, quad->ssamp + 1, quad->esamp - 1,
437 centerLine, centerLine, 4)) {
445 for (
int i = quad->sline; i <= quad->eline; i++) {
446 for (
int j = quad->ssamp; j <= quad->esamp; j++) {
447 lineMap[i-quad->slineTile][j-quad->ssampTile] = NULL8;
451 quadTree.erase(quadTree.begin());
475 if ((quad->eline - quad->sline) < p_endQuadSize) {
476 SlowQuad(quadTree, trans, lineMap, sampMap);
489 for (
int i = 0; i < 4; i++) {
492 A[i][2] = oline[i] * osamp[i];
500 if ((detA = Det4x4(A)) == 0.0) {
501 if ((quad->eline - quad->sline) < p_endQuadSize) {
502 SlowQuad(quadTree, trans, lineMap, sampMap);
514 for (
int j = 0; j < 4; j++) {
515 memmove(B, A, 16 *
sizeof(
double));
517 for (
int i = 0; i < 4; i++) {
521 lineCoef[j] = Det4x4(B) / detA;
526 for (
int j = 0; j < 4; j++) {
527 memmove(B, A, 16 *
sizeof(
double));
529 for (
int i = 0; i < 4; i++) {
533 sampCoef[j] = Det4x4(B) / detA;
537 double quadMidLine = (quad->sline + quad->eline) / 2.0;
538 double quadMidSamp = (quad->ssamp + quad->esamp) / 2.0;
539 double midLine, midSamp;
541 if (!trans.Xform(midSamp, midLine, quadMidSamp, quadMidLine)) {
542 if ((quad->eline - quad->sline) < p_endQuadSize) {
543 SlowQuad(quadTree, trans, lineMap, sampMap);
551 double cmidLine = lineCoef[0] * quadMidLine +
552 lineCoef[1] * quadMidSamp +
553 lineCoef[2] * quadMidLine * quadMidSamp +
556 double cmidSamp = sampCoef[0] * quadMidLine +
557 sampCoef[1] * quadMidSamp +
558 sampCoef[2] * quadMidLine * quadMidSamp +
561 if ((abs(cmidSamp - midSamp) > 0.5) || (abs(cmidLine - midLine) > 0.5)) {
562 if ((quad->eline - quad->sline) < p_endQuadSize) {
563 SlowQuad(quadTree, trans, lineMap, sampMap);
573 double ulLine = lineCoef[0] * (double) quad->sline +
574 lineCoef[1] * (
double) quad->ssamp +
575 lineCoef[2] * (double) quad->sline * (
double) quad->ssamp +
578 double ulSamp = sampCoef[0] * (double) quad->sline +
579 sampCoef[1] * (
double) quad->ssamp +
580 sampCoef[2] * (double) quad->sline * (
double) quad->ssamp +
585 double lineChangeWrLine = lineCoef[0] + lineCoef[2] * (double) quad->ssamp;
586 double sampChangeWrLine = sampCoef[0] + sampCoef[2] * (double) quad->ssamp;
588 for (
int ol = quad->sline; ol <= quad->eline; ol++) {
591 double lineChangeWrSamp = lineCoef[1] + lineCoef[2] * (double) ol;
592 double sampChangeWrSamp = sampCoef[1] + sampCoef[2] * (double) ol;
595 double cline = ulLine;
596 double csamp = ulSamp;
599 int startSamp = quad->ssamp - quad->ssampTile;
600 std::vector<double> &lineVect = lineMap[ol-quad->slineTile];
601 std::vector<double> &sampleVect = sampMap[ol-quad->slineTile];
604 for (
int os = quad->ssamp; os <= quad->esamp; os++) {
605 lineVect[startSamp] = cline;
606 sampleVect[startSamp] = csamp;
610 cline += lineChangeWrSamp;
611 csamp += sampChangeWrSamp;
615 ulLine += lineChangeWrLine;
616 ulSamp += sampChangeWrLine;
621 quadTree.erase(quadTree.begin());
626 void ProcessRubberSheet::SplitQuad(std::vector<Quad *> &quadTree) {
629 Quad *quad = quadTree[0];
630 int n = (quad->eline - quad->sline + 1) / 2;
635 q1->eline = quad->sline + n - 1;
636 q1->esamp = quad->ssamp + n - 1;
637 quadTree.push_back(q1);
642 q2->eline = quad->sline + n - 1;
643 q2->ssamp = quad->ssamp + n;
644 quadTree.push_back(q2);
649 q3->sline = quad->sline + n;
650 q3->esamp = quad->ssamp + n - 1;
651 quadTree.push_back(q3);
656 q4->sline = quad->sline + n;
657 q4->ssamp = quad->ssamp + n;
658 quadTree.push_back(q4);
662 quadTree.erase(quadTree.begin());
667 void ProcessRubberSheet::SlowQuad(std::vector<Quad *> &quadTree,
669 std::vector< std::vector<double> > &lineMap,
670 std::vector< std::vector<double> > &sampMap) {
673 Quad *quad = quadTree[0];
677 for (
int oline = quad->sline; oline <= quad->eline; oline++) {
678 int lineIndex = oline - quad->slineTile;
679 for (
int osamp = quad->ssamp; osamp <= quad->esamp; osamp++) {
680 int sampIndex = osamp - quad->ssampTile;
681 lineMap[lineIndex][sampIndex] = NULL8;
682 if (trans.Xform(isamp, iline, (
double) osamp, (
double) oline)) {
683 if ((isamp >= 0.5) ||
685 (iline <=
InputCubes[0]->lineCount() + 0.5) ||
686 (isamp <=
InputCubes[0]->sampleCount() + 0.5)) {
687 lineMap[lineIndex][sampIndex] = iline;
688 sampMap[lineIndex][sampIndex] = isamp;
696 quadTree.erase(quadTree.begin());
701 double ProcessRubberSheet::Det4x4(
double m[4][4]) {
705 cofact [0][0] = m[1][1];
706 cofact [0][1] = m[1][2];
707 cofact [0][2] = m[1][3];
708 cofact [1][0] = m[2][1];
709 cofact [1][1] = m[2][2];
710 cofact [1][2] = m[2][3];
711 cofact [2][0] = m[3][1];
712 cofact [2][1] = m[3][2];
713 cofact [2][2] = m[3][3];
714 double det = m[0][0] * Det3x3(cofact);
716 cofact [0][0] = m[1][0];
717 cofact [0][1] = m[1][2];
718 cofact [0][2] = m[1][3];
719 cofact [1][0] = m[2][0];
720 cofact [1][1] = m[2][2];
721 cofact [1][2] = m[2][3];
722 cofact [2][0] = m[3][0];
723 cofact [2][1] = m[3][2];
724 cofact [2][2] = m[3][3];
725 det -= m[0][1] * Det3x3(cofact);
727 cofact [0][0] = m[1][0];
728 cofact [0][1] = m[1][1];
729 cofact [0][2] = m[1][3];
730 cofact [1][0] = m[2][0];
731 cofact [1][1] = m[2][1];
732 cofact [1][2] = m[2][3];
733 cofact [2][0] = m[3][0];
734 cofact [2][1] = m[3][1];
735 cofact [2][2] = m[3][3];
736 det += m[0][2] * Det3x3(cofact);
738 cofact [0][0] = m[1][0];
739 cofact [0][1] = m[1][1];
740 cofact [0][2] = m[1][2];
741 cofact [1][0] = m[2][0];
742 cofact [1][1] = m[2][1];
743 cofact [1][2] = m[2][2];
744 cofact [2][0] = m[3][0];
745 cofact [2][1] = m[3][1];
746 cofact [2][2] = m[3][2];
747 det -= m[0][3] * Det3x3(cofact);
754 double ProcessRubberSheet::Det3x3(
double m[3][3]) {
756 return m[0][0] * m[1][1] * m[2][2] -
757 m[0][0] * m[1][2] * m[2][1] -
758 m[0][1] * m[1][0] * m[2][2] +
759 m[0][1] * m[1][2] * m[2][0] +
760 m[0][2] * m[1][0] * m[2][1] -
761 m[0][2] * m[1][1] * m[2][0];
792 string m =
"You must specify exactly one input cube";
796 string m =
"You must specify exactly one output cube";
801 Portal iportal(interp.Samples(), interp.Lines(),
803 interp.HotSample(), interp.HotLine());
806 int patchesPerBand = 0;
807 for (
int line = m_patchStartLine; line <=
InputCubes[0]->lineCount();
808 line += m_patchLineIncrement) {
809 for (
int samp = m_patchStartSample;
811 samp += m_patchSampleIncrement) {
816 int patchCount =
InputCubes[0]->bandCount() * patchesPerBand;
840 for (
int band=1; band <=
InputCubes[0]->bandCount(); band++) {
841 if (p_bandChangeFunct != NULL) p_bandChangeFunct(band);
842 iportal.SetPosition(1,1,band);
844 for (
int line = m_patchStartLine;
846 line += m_patchLineIncrement) {
847 for (
int samp = m_patchStartSample;
850 transformPatch((
double)samp, (
double)(samp + m_patchSamples - 1),
851 (
double)line, (
double)(line + m_patchLines - 1),
852 iportal, trans, interp);
860 void ProcessRubberSheet::transformPatch(
double ssamp,
double esamp,
861 double sline,
double eline,
869 if (ssamp == esamp) ssamp = esamp - 1;
873 if (sline == eline) sline = eline - 1;
878 QVector<double> isamps;
879 QVector<double> ilines;
880 QVector<double> osamps;
881 QVector<double> olines;
885 if (trans.Xform(tsamp,tline,ssamp,sline)) {
886 isamps.push_back(ssamp);
887 ilines.push_back(sline);
888 osamps.push_back(tsamp);
889 olines.push_back(tline);
893 if (trans.Xform(tsamp,tline,esamp,sline)) {
894 isamps.push_back(esamp);
895 ilines.push_back(sline);
896 osamps.push_back(tsamp);
897 olines.push_back(tline);
901 if (trans.Xform(tsamp,tline,ssamp,eline)) {
902 isamps.push_back(ssamp);
903 ilines.push_back(eline);
904 osamps.push_back(tsamp);
905 olines.push_back(tline);
909 if (trans.Xform(tsamp,tline,esamp,eline)) {
910 isamps.push_back(esamp);
911 ilines.push_back(eline);
912 osamps.push_back(tsamp);
913 olines.push_back(tline);
918 if (isamps.size() == 0) {
923 if (isamps.size() < 4) {
924 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
929 int osampMin = (int) osamps[0];
930 int osampMax = (int) (osamps[0] + 0.5);
931 int olineMin = (int) olines[0];
932 int olineMax = (int) (olines[0] + 0.5);
933 for (
int i = 1; i < osamps.size(); i++) {
934 if (osamps[i] < osampMin) osampMin = (int) osamps[i];
935 if (osamps[i] > osampMax) osampMax = (int) (osamps[i] + 0.5);
936 if (olines[i] < olineMin) olineMin = (int) olines[i];
937 if (olines[i] > olineMax) olineMax = (int) (olines[i] + 0.5);
942 if (osampMax < 1)
return;
943 if (olineMax < 1)
return;
944 if (osampMin >
OutputCubes[0]->sampleCount())
return;
945 if (olineMin >
OutputCubes[0]->lineCount())
return;
948 if (osampMin < 1) osampMin = 1;
949 if (olineMin < 1) olineMin = 1;
966 if (osampMax - osampMin + 1.0 >
OutputCubes[0]->sampleCount() * 0.50) {
967 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
970 if (olineMax - olineMin + 1.0 >
OutputCubes[0]->lineCount() * 0.50) {
971 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
976 BasisFunction isampFunc(
"Ax+By+C",3,3);
977 LeastSquares isampLSQ(isampFunc);
979 BasisFunction ilineFunc(
"Dx+Ey+F",3,3);
980 LeastSquares ilineLSQ(ilineFunc);
983 for (
int i=0; i < isamps.size(); i++) {
984 std::vector<double> vars;
985 vars.push_back(osamps[i]);
986 vars.push_back(olines[i]);
989 isampLSQ.AddKnown(vars,isamps[i]);
990 ilineLSQ.AddKnown(vars,ilines[i]);
996 catch (IException &e) {
997 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
1002 for (
int i=0; i<isamps.size(); i++) {
1003 if (fabs(isampLSQ.Residual(i)) > 0.5) {
1004 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
1007 if (fabs(ilineLSQ.Residual(i)) > 0.5) {
1008 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
1017 double csamp = (ssamp + esamp) / 2.0;
1018 double cline = (sline + eline) / 2.0;
1019 if (trans.Xform(tsamp,tline,csamp,cline)) {
1020 std::vector<double> vars;
1021 vars.push_back(tsamp);
1022 vars.push_back(tline);
1023 vars.push_back(1.0);
1025 double isamp = isampFunc.Evaluate(vars);
1026 double iline = ilineFunc.Evaluate(vars);
1028 double err = (csamp - isamp) * (csamp - isamp) +
1029 (cline - iline) * (cline - iline);
1031 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
1036 splitPatch(ssamp, esamp, sline, eline, iportal, trans, interp);
1041 double A = isampFunc.Coefficient(0);
1042 double B = isampFunc.Coefficient(1);
1043 double C = isampFunc.Coefficient(2);
1045 double D = ilineFunc.Coefficient(0);
1046 double E = ilineFunc.Coefficient(1);
1047 double F = ilineFunc.Coefficient(2);
1052 Brick oBrick(*
OutputCubes[0], osampMax-osampMin+1, olineMax-olineMin+1, 1);
1053 oBrick.SetBasePosition(osampMin, olineMin, iportal.Band());
1056 bool foundNull =
false;
1057 for (
int oline = olineMin; oline <= olineMax; oline++) {
1058 double isamp = A * osampMin + B * oline + C;
1059 double iline = D * osampMin +
E * oline + F;
1060 double isampChangeWRTosamp = A;
1061 double ilineChangeWRTosamp = D;
1062 for (
int osamp = osampMin; osamp <= osampMax;
1063 osamp++, isamp += isampChangeWRTosamp, iline += ilineChangeWRTosamp) {
1065 iportal.SetPosition(isamp, iline, iportal.Band());
1067 double dn = interp.Interpolate(isamp, iline, iportal.DoubleBuffer());
1068 oBrick[brickIndex] = dn;
1069 if (dn ==
Null) foundNull =
true;
1086 Brick readBrick(*
OutputCubes[0], osampMax-osampMin+1, olineMax-olineMin+1, 1);
1087 readBrick.SetBasePosition(osampMin, olineMin, iportal.Band());
1089 for (brickIndex = 0; brickIndex<(osampMax-osampMin+1)*(olineMax-olineMin+1); brickIndex++) {
1090 if (readBrick[brickIndex] !=
Null) {
1091 oBrick[brickIndex] = readBrick[brickIndex];
1103 void ProcessRubberSheet::splitPatch(
double ssamp,
double esamp,
1104 double sline,
double eline, Portal &iportal,
1105 Transform &trans, Interpolator &interp) {
1108 if ((esamp - ssamp < 0.1) && (eline - sline < 0.1))
return;
1111 double midSamp = (esamp + ssamp) / 2.0;
1112 double midLine = (eline + sline) / 2.0;
1114 transformPatch(ssamp, midSamp,
1116 iportal, trans, interp);
1117 transformPatch(midSamp, esamp,
1119 iportal, trans, interp);
1120 transformPatch(ssamp, midSamp,
1122 iportal, trans, interp);
1123 transformPatch(midSamp, esamp,
1125 iportal, trans, interp);
This algorithm is designed for applications that jump around between a couple of spots in the cube wi...
@ Programmer
This error is for when a programmer made an API call that was illegal.
Buffer for containing a two dimensional section of an image.
std::vector< Isis::Cube * > InputCubes
A vector of pointers to opened Cube objects.
Isis::Progress * p_progress
Pointer to a Progress object.
std::vector< Isis::Cube * > OutputCubes
A vector of pointers to allocated Cube objects.
virtual void StartProcess(Transform &trans, Interpolator &interp)
Applies a Transform and an Interpolator to every pixel in the output cube.
virtual void processPatchTransform(Transform &trans, Interpolator &interp)
Applies a Transform and an Interpolator to small patches.
ProcessRubberSheet(int startSize=128, int endSize=8)
Constructs a ProcessRubberSheet class with the default tile size range.
virtual void BandChange(void(*funct)(const int band))
Registers a function to be called when the current output cube band number changes.
virtual void setPatchParameters(int startSample, int startLine, int samples, int lines, int sampleIncrement, int lineIncrement)
This method allows the programmer to override the default values for patch parameters used in the pat...
bool TestLine(Transform &trans, int ssamp, int esamp, int sline, int eline, int increment)
This function walks a line (or rectangle) and tests a point every increment pixels.
void SetMaximumSteps(const int steps)
This sets the maximum number of steps in the process.
void CheckStatus()
Checks and updates the status.
Buffer manager, for moving through a cube in tiles.
This algorithm is designed for applications that jump around between a couple of spots in the cube wi...
const double E
Sets some basic constants for use in ISIS programming.
This is free and unencumbered software released into the public domain.
const double Null
Value for an Isis Null pixel.
Namespace for the standard library.