14 #include "BasisFunction.h"
15 #include "BoxcarCachingAlgorithm.h"
17 #include "Interpolator.h"
18 #include "LeastSquares.h"
20 #include "ProcessRubberSheet.h"
21 #include "TileManager.h"
22 #include "Transform.h"
23 #include "UniqueIOCachingAlgorithm.h"
35 ProcessRubberSheet::ProcessRubberSheet(
int startSize,
int endSize) {
37 p_bandChangeFunct = NULL;
42 p_startQuadSize = startSize;
43 p_endQuadSize = endSize;
46 m_patchStartSample = 1;
50 m_patchSampleIncrement = 4;
51 m_patchLineIncrement = 4;
102 void ProcessRubberSheet::setPatchParameters(
int startSample,
int startLine,
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;
136 if (InputCubes.size() != 1) {
137 string m =
"You must specify exactly one input cube";
138 throw IException(IException::Programmer, m, _FILEINFO_);
140 else if (OutputCubes.size() != 1) {
141 string m =
"You must specify exactly one output cube";
142 throw IException(IException::Programmer, m, _FILEINFO_);
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);
155 TileManager otile(*OutputCubes[0], p_startQuadSize, p_startQuadSize);
159 InputCubes[0]->pixelType() ,
163 p_progress->SetMaximumSteps(otile.
Tiles());
164 p_progress->CheckStatus();
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++) {
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;
189 OutputCubes[0]->write(otile);
190 p_progress->CheckStatus();
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);
212 OutputCubes[0]->write(otile);
213 p_progress->CheckStatus();
232 void ProcessRubberSheet::BandChange(
void (*funct)(
const int band)) {
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);
259 InputCubes[0]->read(iportal);
260 otile[i] = interp.
Interpolate(inputSamp, inputLine,
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);
306 InputCubes[0]->read(iportal);
307 otile[i] = interp.Interpolate(inputSamp, inputLine,
308 iportal.DoubleBuffer());
330 bool ProcessRubberSheet::TestLine(
Transform &trans,
int ssamp,
int esamp,
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];
787 void ProcessRubberSheet::processPatchTransform(
Transform &trans,
791 if (InputCubes.size() != 1) {
792 string m =
"You must specify exactly one input cube";
793 throw IException(IException::Programmer, m, _FILEINFO_);
795 else if (OutputCubes.size() != 1) {
796 string m =
"You must specify exactly one output cube";
797 throw IException(IException::Programmer, m, _FILEINFO_);
802 InputCubes[0]->pixelType() ,
806 int patchesPerBand = 0;
807 for (
int line = m_patchStartLine; line <= InputCubes[0]->lineCount();
808 line += m_patchLineIncrement) {
809 for (
int samp = m_patchStartSample;
810 samp <= InputCubes[0]->sampleCount();
811 samp += m_patchSampleIncrement) {
816 int patchCount = InputCubes[0]->bandCount() * patchesPerBand;
817 p_progress->SetMaximumSteps(patchCount);
818 p_progress->CheckStatus();
840 for (
int band=1; band <= InputCubes[0]->bandCount(); band++) {
841 if (p_bandChangeFunct != NULL) p_bandChangeFunct(band);
844 for (
int line = m_patchStartLine;
845 line <= InputCubes[0]->lineCount();
846 line += m_patchLineIncrement) {
847 for (
int samp = m_patchStartSample;
848 samp <= InputCubes[0]->sampleCount();
849 samp += m_patchSampleIncrement, p_progress->CheckStatus()) {
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,
867 if (esamp > InputCubes[0]->sampleCount()) {
868 esamp = InputCubes[0]->sampleCount();
869 if (ssamp == esamp) ssamp = esamp - 1;
871 if (eline > InputCubes[0]->lineCount()) {
872 eline = InputCubes[0]->lineCount();
873 if (sline == eline) sline = eline - 1;
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;
950 if (osampMax > OutputCubes[0]->sampleCount()) {
951 osampMax = OutputCubes[0]->sampleCount();
953 if (olineMax > OutputCubes[0]->lineCount()) {
954 olineMax = OutputCubes[0]->lineCount();
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]);
993 isampLSQ.Solve(LeastSquares::QRD);
994 ilineLSQ.Solve(LeastSquares::QRD);
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) {
1066 InputCubes[0]->read(iportal);
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());
1088 OutputCubes[0]->read(readBrick);
1089 for (brickIndex = 0; brickIndex<(osampMax-osampMin+1)*(olineMax-olineMin+1); brickIndex++) {
1090 if (readBrick[brickIndex] != Null) {
1091 oBrick[brickIndex] = readBrick[brickIndex];
1097 OutputCubes[0]->write(oBrick);
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);