/*
* Copyright (C) 2013 Dr. John Lindsay <jlindsay@uoguelph.ca>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package plugins;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.event.ChangeListener;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.util.Date;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.table.*;
import javax.swing.event.TableModelListener;
import org.apache.commons.math3.linear.*;
import whitebox.geospatialfiles.ShapeFile;
import whitebox.geospatialfiles.WhiteboxRaster;
import whitebox.geospatialfiles.shapefile.*;
import static whitebox.geospatialfiles.shapefile.ShapeType.POINT;
import static whitebox.geospatialfiles.shapefile.ShapeType.POINTM;
import static whitebox.geospatialfiles.shapefile.ShapeType.POINTZ;
import whitebox.interfaces.WhiteboxPluginHost;
import whitebox.structures.XYPoint;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ResourceBundle;
/**
* Can't find
* @author Dr. John Lindsay email: jlindsay@uoguelph.ca
*/
public class ImageRectificationPanel extends JPanel implements ActionListener,
ChangeListener, TableModelListener, PropertyChangeListener, MouseListener {
// global variables
private String inputImageFile;
private String imageGCPFile;
private String mapGCPFile;
private String outputImageFile;
private int polyOrder = 1;
private double[] forwardRegressCoeffX;
private double[] forwardRegressCoeffY;
private double[] backRegressCoeffX;
private double[] backRegressCoeffY;
private int numCoefficients;
private double[] imageGCPsXCoords;
private double[] imageGCPsYCoords;
private double[] mapGCPsXCoords;
private double[] mapGCPsYCoords;
private double[] residualsXY;
private boolean[] useGCP;
private double imageXMin;
private double imageYMin;
private double mapXMin;
private double mapYMin;
private WhiteboxPluginHost myHost;
private JSpinner polyOrderSpinner;
private JTable dataTable;
private JProgressBar progressBar;
private Task task;
private JLabel cancel;
private ResourceBundle bundle;
private ResourceBundle messages;
// constructors
public ImageRectificationPanel() {
// no-args constructor
}
public ImageRectificationPanel(String inputImageFile, String imageGCPFile,
String mapGCPFile, String outputImageFile, WhiteboxPluginHost host) {
this.imageGCPFile = imageGCPFile;
this.inputImageFile = inputImageFile;
this.mapGCPFile = mapGCPFile;
this.outputImageFile = outputImageFile;
this.myHost = host;
this.bundle = host.getGuiLabelsBundle();
this.messages = host.getMessageBundle();
readFiles();
createGui();
}
// properties
public String getInputImageFile() {
return inputImageFile;
}
public void setInputImageFile(String inputImageFile) {
this.inputImageFile = inputImageFile;
}
public String getImageGCPFile() {
return imageGCPFile;
}
public void setImageGCPFile(String imageGCPFile) {
this.imageGCPFile = imageGCPFile;
}
public String getMapGCPFile() {
return mapGCPFile;
}
public void setMapGCPFile(String mapGCPFile) {
this.mapGCPFile = mapGCPFile;
}
public String getOutputImageFile() {
return outputImageFile;
}
public void setOutputImageFile(String outputImageFile) {
this.outputImageFile = outputImageFile;
}
public int getPolyOrder() {
return polyOrder;
}
public void setPolyOrder(int polyOrder) {
this.polyOrder = polyOrder;
}
// methods
public final void createGui() {
this.removeAll();
if (imageGCPsXCoords == null) {
return;
}
int i;
int newN = 0;
for (i = 0; i < imageGCPsXCoords.length; i++) {
if (useGCP[i]) {
newN++;
}
}
double[] X1 = new double[newN];
double[] Y1 = new double[newN];
double[] X2 = new double[newN];
double[] Y2 = new double[newN];
int j = 0;
for (i = 0; i < imageGCPsXCoords.length; i++) {
if (useGCP[i]) {
X1[j] = imageGCPsXCoords[i];
Y1[j] = imageGCPsYCoords[i];
X2[j] = mapGCPsXCoords[i];
Y2[j] = mapGCPsYCoords[i];
j++;
}
}
calculateEquations(X1, Y1, X2, Y2);
// gui stuff
this.setLayout(new BorderLayout());
DecimalFormat df = new DecimalFormat("###,###,##0.000");
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
JButton btnOK = createButton(bundle.getString("OK"), bundle.getString("OK"), "ok");
JButton btnExit = createButton(bundle.getString("Close"), bundle.getString("Close"), "close");
//JButton btnRefresh = createButton("Cancel", "Cancel");
buttonPane.add(Box.createHorizontalStrut(10));
buttonPane.add(btnOK);
buttonPane.add(Box.createHorizontalStrut(5));
//buttonPane.add(btnRefresh);
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(btnExit);
buttonPane.add(Box.createHorizontalGlue());
progressBar = new JProgressBar(0, 100);
buttonPane.add(progressBar);
buttonPane.add(Box.createHorizontalStrut(5));
cancel = new JLabel(bundle.getString("Cancel"));
cancel.setForeground(Color.BLUE.darker());
cancel.addMouseListener(this);
buttonPane.add(cancel);
buttonPane.add(Box.createHorizontalStrut(10));
this.add(buttonPane, BorderLayout.SOUTH);
Box mainBox = Box.createVerticalBox();
mainBox.add(Box.createVerticalStrut(10));
Box box1 = Box.createHorizontalBox();
box1.add(Box.createHorizontalStrut(10));
box1.add(new JLabel(bundle.getString("PolynomialOrder") + ": "));
SpinnerModel model =
new SpinnerNumberModel(polyOrder, //initial value
1, //min
5, //max
1); //step
polyOrderSpinner = new JSpinner(model);
polyOrderSpinner.setPreferredSize(new Dimension(15,
polyOrderSpinner.getPreferredSize().height));
polyOrderSpinner.addChangeListener(this);
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) polyOrderSpinner.getEditor();
editor.getTextField().setEnabled(true);
editor.getTextField().setEditable(false);
box1.add(polyOrderSpinner);
box1.add(Box.createHorizontalGlue());
JLabel label = new JLabel("RMSE: " + df.format(overallRMSE));
box1.add(label);
box1.add(Box.createHorizontalStrut(10));
mainBox.add(box1);
mainBox.add(Box.createVerticalStrut(10));
// Create columns names
int numPoints = imageGCPsXCoords.length;
Object dataValues[][] = new Object[numPoints][7];
j = 0;
for (i = 0; i < numPoints; i++) {
dataValues[i][0] = i + 1;
dataValues[i][1] = df.format(imageGCPsXCoords[i]);
dataValues[i][2] = df.format(imageGCPsYCoords[i]);
dataValues[i][3] = df.format(mapGCPsXCoords[i]);
dataValues[i][4] = df.format(mapGCPsYCoords[i]);
if (useGCP[i]) {
dataValues[i][5] = df.format(residualsXY[j]);
j++;
} else {
dataValues[i][5] = null;
}
dataValues[i][6] = useGCP[i];
}
String columnNames[] = {"GCP", bundle.getString("Image") + " X",
bundle.getString("Image") + " Y", bundle.getString("Map") + " X",
bundle.getString("Map") + " Y", messages.getString("Error"), "Use"};
DefaultTableModel tableModel = new DefaultTableModel(dataValues, columnNames);
dataTable = new JTable(tableModel) {
private static final long serialVersionUID = 1L;
@Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return Integer.class;
case 1:
return String.class; //Double.class;
case 2:
return String.class; //Double.class;
case 3:
return String.class; //Double.class;
case 4:
return String.class; //Double.class;
case 5:
return String.class; //Double.class;
case 6:
return Boolean.class;
default:
return String.class; //Double.class;
}
}
@Override
public Component prepareRenderer(TableCellRenderer renderer, int index_row, int index_col) {
Component comp = super.prepareRenderer(renderer, index_row, index_col);
//even index, selected or not selected
if (index_row % 2 == 0) {
comp.setBackground(Color.WHITE);
comp.setForeground(Color.BLACK);
} else {
comp.setBackground(new Color(225, 245, 255)); //new Color(210, 230, 255));
comp.setForeground(Color.BLACK);
}
if (isCellSelected(index_row, index_col)) {
comp.setForeground(Color.RED);
}
return comp;
}
};
tableModel.addTableModelListener(this);
TableCellRenderer rend = dataTable.getTableHeader().getDefaultRenderer();
TableColumnModel tcm = dataTable.getColumnModel();
//for (int j = 0; j < tcm.getColumnCount(); j += 1) {
TableColumn tc = tcm.getColumn(0);
TableCellRenderer rendCol = tc.getHeaderRenderer(); // likely null
if (rendCol == null) {
rendCol = rend;
}
Component c = rendCol.getTableCellRendererComponent(dataTable, tc.getHeaderValue(), false, false, 0, 0);
tc.setPreferredWidth(35);
tc = tcm.getColumn(6);
rendCol = tc.getHeaderRenderer(); // likely null
if (rendCol == null) {
rendCol = rend;
}
c = rendCol.getTableCellRendererComponent(dataTable, tc.getHeaderValue(), false, false, 0, 6);
tc.setPreferredWidth(35);
JScrollPane scroll = new JScrollPane(dataTable);
mainBox.add(scroll);
this.add(mainBox, BorderLayout.CENTER);
this.validate();
}
private JButton createButton(String buttonLabel, String toolTip, String actionCommand) {
JButton btn = new JButton(buttonLabel);
btn.addActionListener(this);
btn.setActionCommand(actionCommand);
btn.setToolTipText(toolTip);
return btn;
}
private void readFiles() {
try {
if (imageGCPFile == null || mapGCPFile == null) {
return;
}
int i;
ShapeFile imageGCPs = new ShapeFile(imageGCPFile);
ShapeFile mapGCPs = new ShapeFile(mapGCPFile);
int n = imageGCPs.getNumberOfRecords();
if (n != mapGCPs.getNumberOfRecords()) {
showFeedback("Shapefiles must have the same number of GCPs.");
return;
}
if (imageGCPs.getShapeType().getBaseType() != ShapeType.POINT
|| mapGCPs.getShapeType().getBaseType() != ShapeType.POINT) {
showFeedback("Shapefiles must be of Point ShapeType. \n"
+ "The operation will not continue.");
return;
}
// Read the GCP data
imageGCPsXCoords = new double[n];
imageGCPsYCoords = new double[n];
mapGCPsXCoords = new double[n];
mapGCPsYCoords = new double[n];
i = 0;
for (ShapeFileRecord record : imageGCPs.records) {
double[][] vertices = new double[1][1];
ShapeType shapeType = record.getShapeType();
switch (shapeType) {
case POINT:
whitebox.geospatialfiles.shapefile.Point recPoint =
(whitebox.geospatialfiles.shapefile.Point) (record.getGeometry());
vertices = recPoint.getPoints();
break;
case POINTZ:
PointZ recPointZ = (PointZ) (record.getGeometry());
vertices = recPointZ.getPoints();
break;
case POINTM:
PointM recPointM = (PointM) (record.getGeometry());
vertices = recPointM.getPoints();
break;
default:
showFeedback("Shapefiles must be of Point ShapeType. \n"
+ "The operation will not continue.");
return;
}
imageGCPsXCoords[i] = vertices[0][0];// - imageXMin;
imageGCPsYCoords[i] = vertices[0][1];// - imageYMin;
i++;
}
i = 0;
for (ShapeFileRecord record : mapGCPs.records) {
double[][] vertices = new double[1][1];
ShapeType shapeType = record.getShapeType();
switch (shapeType) {
case POINT:
whitebox.geospatialfiles.shapefile.Point recPoint =
(whitebox.geospatialfiles.shapefile.Point) (record.getGeometry());
vertices = recPoint.getPoints();
break;
case POINTZ:
PointZ recPointZ = (PointZ) (record.getGeometry());
vertices = recPointZ.getPoints();
break;
case POINTM:
PointM recPointM = (PointM) (record.getGeometry());
vertices = recPointM.getPoints();
break;
default:
showFeedback("Shapefiles must be of Point ShapeType. \n"
+ "The operation will not continue.");
return;
}
mapGCPsXCoords[i] = vertices[0][0];// - mapXMin;
mapGCPsYCoords[i] = vertices[0][1];// - mapYMin;
i++;
}
useGCP = new boolean[n];
for (i = 0; i < n; i++) {
useGCP[i] = true;
}
} catch (OutOfMemoryError oe) {
myHost.showFeedback("An out-of-memory error has occurred during operation.");
} catch (Exception e) {
myHost.showFeedback("An error has occurred during operation. See log file for details.");
myHost.logException("Error in ImageRectification", e);
}
}
double overallRMSE = 0.0;
public void calculateEquations(double[] imageX, double[] imageY,
double[] mapX, double[] mapY) {
try {
int m, i, j, k;
int n = mapX.length;
// How many coefficients are there?
numCoefficients = 0;
for (j = 0; j <= polyOrder; j++) {
for (k = 0; k <= (polyOrder - j); k++) {
numCoefficients++;
}
}
for (i = 0; i < n; i++) {
imageX[i] -= imageXMin;
imageY[i] -= imageYMin;
mapX[i] -= mapXMin;
mapY[i] -= mapYMin;
}
// Solve the forward transformation equations
double[][] forwardCoefficientMatrix = new double[n][numCoefficients];
for (i = 0; i < n; i++) {
m = 0;
for (j = 0; j <= polyOrder; j++) {
for (k = 0; k <= (polyOrder - j); k++) {
forwardCoefficientMatrix[i][m] = Math.pow(imageX[i], j) * Math.pow(imageY[i], k);
m++;
}
}
}
RealMatrix coefficients =
new Array2DRowRealMatrix(forwardCoefficientMatrix, false);
//DecompositionSolver solver = new SingularValueDecomposition(coefficients).getSolver();
DecompositionSolver solver = new QRDecomposition(coefficients).getSolver();
// do the x-coordinate first
RealVector constants = new ArrayRealVector(mapX, false);
RealVector solution = solver.solve(constants);
forwardRegressCoeffX = new double[n];
for (int a = 0; a < numCoefficients; a++) {
forwardRegressCoeffX[a] = solution.getEntry(a);
}
double[] residualsX = new double[n];
double SSresidX = 0;
for (i = 0; i < n; i++) {
double yHat = 0.0;
for (j = 0; j < numCoefficients; j++) {
yHat += forwardCoefficientMatrix[i][j] * forwardRegressCoeffX[j];
}
residualsX[i] = mapX[i] - yHat;
SSresidX += residualsX[i] * residualsX[i];
}
double sumX = 0;
double SSx = 0;
for (i = 0; i < n; i++) {
SSx += mapX[i] * mapX[i];
sumX += mapX[i];
}
double varianceX = (SSx - (sumX * sumX) / n) / n;
double SStotalX = (n - 1) * varianceX;
double rsqX = 1 - SSresidX / SStotalX;
//System.out.println("x-coordinate r-square: " + rsqX);
// now the y-coordinate
constants = new ArrayRealVector(mapY, false);
solution = solver.solve(constants);
forwardRegressCoeffY = new double[numCoefficients];
for (int a = 0; a < numCoefficients; a++) {
forwardRegressCoeffY[a] = solution.getEntry(a);
}
double[] residualsY = new double[n];
residualsXY = new double[n];
double SSresidY = 0;
for (i = 0; i < n; i++) {
double yHat = 0.0;
for (j = 0; j < numCoefficients; j++) {
yHat += forwardCoefficientMatrix[i][j] * forwardRegressCoeffY[j];
}
residualsY[i] = mapY[i] - yHat;
SSresidY += residualsY[i] * residualsY[i];
residualsXY[i] = Math.sqrt(residualsX[i] * residualsX[i]
+ residualsY[i] * residualsY[i]);
}
double sumY = 0;
double sumR = 0;
double SSy = 0;
double SSr = 0;
for (i = 0; i < n; i++) {
SSy += mapY[i] * mapY[i];
SSr += residualsXY[i] * residualsXY[i];
sumY += mapY[i];
sumR += residualsXY[i];
}
double varianceY = (SSy - (sumY * sumY) / n) / n;
double varianceResiduals = (SSr - (sumR * sumR) / n) / n;
double SStotalY = (n - 1) * varianceY;
double rsqY = 1 - SSresidY / SStotalY;
overallRMSE = Math.sqrt(varianceResiduals);
//System.out.println("y-coordinate r-square: " + rsqY);
// // Print the residuals.
// System.out.println("\nResiduals:");
// for (i = 0; i < n; i++) {
// System.out.println("Point " + (i + 1) + "\t" + residualsX[i]
// + "\t" + residualsY[i] + "\t" + residualsXY[i]);
// }
// Solve the backward transformation equations
double[][] backCoefficientMatrix = new double[n][numCoefficients];
for (i = 0; i < n; i++) {
m = 0;
for (j = 0; j <= polyOrder; j++) {
for (k = 0; k <= (polyOrder - j); k++) {
backCoefficientMatrix[i][m] = Math.pow(mapX[i], j) * Math.pow(mapY[i], k);
m++;
}
}
}
coefficients = new Array2DRowRealMatrix(backCoefficientMatrix, false);
//DecompositionSolver solver = new SingularValueDecomposition(coefficients).getSolver();
solver = new QRDecomposition(coefficients).getSolver();
// do the x-coordinate first
constants = new ArrayRealVector(imageX, false);
solution = solver.solve(constants);
backRegressCoeffX = new double[numCoefficients];
for (int a = 0; a < numCoefficients; a++) {
backRegressCoeffX[a] = solution.getEntry(a);
}
// now the y-coordinate
constants = new ArrayRealVector(imageY, false);
solution = solver.solve(constants);
backRegressCoeffY = new double[n];
for (int a = 0; a < numCoefficients; a++) {
backRegressCoeffY[a] = solution.getEntry(a);
}
} catch (OutOfMemoryError oe) {
myHost.showFeedback("An out-of-memory error has occurred during operation.");
} catch (Exception e) {
myHost.showFeedback("An error has occurred during operation. See log file for details.");
myHost.logException("Error in ImageRectification", e);
}
}
private XYPoint getForwardCoordinates(double x, double y) {
XYPoint ret;
int j, k, m;
double x_transformed = 0; //mapXMin;
double y_transformed = 0; //mapYMin;
double term;
m = 0;
for (j = 0; j <= polyOrder; j++) {
for (k = 0; k <= (polyOrder - j); k++) {
term = Math.pow(x, j) * Math.pow(y, k);
x_transformed += term * forwardRegressCoeffX[m];
y_transformed += term * forwardRegressCoeffY[m];
m++;
}
}
ret = new XYPoint(x_transformed, y_transformed);
return ret;
}
private XYPoint getBackwardCoordinates(double x, double y) {
XYPoint ret;
int j, k, m;
double x_transformed = 0; //imageXMin;
double y_transformed = 0; //imageYMin;
double term;
m = 0;
for (j = 0; j <= polyOrder; j++) {
for (k = 0; k <= (polyOrder - j); k++) {
term = Math.pow(x, j) * Math.pow(y, k);
x_transformed += term * backRegressCoeffX[m];
y_transformed += term * backRegressCoeffY[m];
m++;
}
}
ret = new XYPoint(x_transformed, y_transformed);
return ret;
}
/**
* Used to communicate feedback pop-up messages between a plugin tool and
* the main Whitebox user-interface.
*
* @param feedback String containing the text to display.
*/
private void showFeedback(String feedback) {
if (myHost != null) {
myHost.showFeedback(feedback);
} else {
System.out.println(feedback);
}
}
/**
* Used to communicate a return object from a plugin tool to the main
* Whitebox user-interface.
*
* @return Object, such as an output WhiteboxRaster.
*/
private void returnData(Object ret) {
if (myHost != null) {
myHost.returnData(ret);
}
}
/**
* Used to communicate a progress update between a plugin tool and the main
* Whitebox user interface.
*
* @param progressLabel A String to use for the progress label.
* @param progress Float containing the progress value (between 0 and 100).
*/
private void updateProgress(String progressLabel, int progress) {
if (myHost != null) {
myHost.updateProgress(progressLabel, progress);
} else {
System.out.println(progressLabel + " " + progress + "%");
}
}
/**
* Used to communicate a progress update between a plugin tool and the main
* Whitebox user interface.
*
* @param progress Float containing the progress value (between 0 and 100).
*/
private void updateProgress(int progressVal) {
progressBar.setValue(progressVal);
// if (myHost != null) {
// myHost.updateProgress(progress);
// } else {
// System.out.println("Progress: " + progress + "%");
// }
}
private boolean cancelOp = false;
/**
* Used to communicate a cancel operation from the Whitebox GUI.
*
* @param cancel Set to true if the plugin should be canceled.
*/
public void setCancelOp(boolean cancel) {
cancelOp = cancel;
}
private void cancelOperation() {
showFeedback("Operation cancelled.");
//updateProgress("Progress: ", 0);
}
//This method is only used during testing.
public static void main(String[] args) {
try {
// int polyOrder = 4;
//// String inputGCPFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/tiepoints 15-16 image 15.shp";
//// String inputRasterFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/A19411_15_Blue.dep";
//// String inputGCPFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/tiepoints 15-16 image 16.shp";
//// String inputRasterFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/A19411_16_Blue.dep";
//// String outputRasterFile = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/16 registered.dep";
//
//// String inputGCPFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/tiepoints final image 15-16.shp";
//// String inputRasterFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/tmp6.dep";
//// String inputGCPFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/tiepoints final image 17.shp";
//// String inputRasterFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/17 adjusted.dep";
//// String outputRasterFile = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/17 registered.dep";
//
//// String inputGCPFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/image 15 GCPs map.shp";
//// String inputRasterFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/A19411_15_Blue.dep";
//// String inputGCPFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/image 15 GCPs.shp";
//// String outputRasterFile = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/15 registered to map1.dep";
//
// String inputGCPFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/image 16 GCPs map.shp";
// String inputRasterFile1 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/A19411_16_Blue.dep";
// String inputGCPFile2 = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/image 16 GCPs.shp";
// String outputRasterFile = "/Users/johnlindsay/Documents/Data/Guelph Photomosaic/16 registered to map1.dep";
//
//
// args = new String[5];
// args[0] = inputGCPFile1;
// args[1] = inputRasterFile1;
// args[2] = inputGCPFile2;
// args[3] = outputRasterFile;
// args[4] = String.valueOf(polyOrder);
//
// TiePointTransformation tpt = new TiePointTransformation();
// tpt.setArgs(args);
// tpt.run();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
boolean isRunning = false;
@Override
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand().toLowerCase();
switch (ac) {
case "close":
JDialog d = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this);
d.dispose();
cancelOp = true;
break;
case "ok":
if (!isRunning) { // you only want one of these threads running at a time.
cancelOp = false;
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
}
break;
case "cancel":
cancelOp = true;
break;
}
}
@Override
public void stateChanged(ChangeEvent e) {
SpinnerModel model = polyOrderSpinner.getModel();
if (model instanceof SpinnerNumberModel) {
polyOrder = (int) (((SpinnerNumberModel) model).getValue());
createGui();
}
}
@Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
int column = e.getColumn();
if (column == 6) {
int row = e.getFirstRow();
useGCP[row] = (boolean) (dataTable.getValueAt(row, column));
createGui();
}
}
}
/**
* Invoked when task's progress property changes.
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("progress")) {
int progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
cancel.setForeground(Color.RED.darker());
}
@Override
public void mouseReleased(MouseEvent e) {
cancel.setForeground(Color.BLUE.darker());
cancelOp = true;
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
class Task extends SwingWorker<Void, Void> {
/*
* Main task. Executed in background thread.
*/
@Override
public Void doInBackground() {
try {
WhiteboxRaster inputImage = new WhiteboxRaster(inputImageFile, "r");
double image2North = inputImage.getNorth();
double image2South = inputImage.getSouth();
double image2West = inputImage.getWest();
double image2East = inputImage.getEast();
XYPoint topLeftCorner = getForwardCoordinates(image2West, image2North);
XYPoint topRightCorner = getForwardCoordinates(image2East, image2North);
XYPoint bottomLeftCorner = getForwardCoordinates(image2West, image2South);
XYPoint bottomRightCorner = getForwardCoordinates(image2East, image2South);
// figure out the grid resolution
double vertCornerDist = Math.sqrt((topLeftCorner.x - bottomLeftCorner.x)
* (topLeftCorner.x - bottomLeftCorner.x)
+ (topLeftCorner.y - bottomLeftCorner.y)
* (topLeftCorner.y - bottomLeftCorner.y));
double horizCornerDist = Math.sqrt((topLeftCorner.x - topRightCorner.x)
* (topLeftCorner.x - topRightCorner.x)
+ (topLeftCorner.y - topRightCorner.y)
* (topLeftCorner.y - topRightCorner.y));
double avgGridRes = (vertCornerDist / inputImage.getNumberRows()
+ horizCornerDist / inputImage.getNumberColumns()) / 2.0;
double outputNorth = Double.NEGATIVE_INFINITY;
double outputSouth = Double.POSITIVE_INFINITY;
double outputEast = Double.NEGATIVE_INFINITY;
double outputWest = Double.POSITIVE_INFINITY;
if (topLeftCorner.y > outputNorth) {
outputNorth = topLeftCorner.y;
}
if (topLeftCorner.y < outputSouth) {
outputSouth = topLeftCorner.y;
}
if (topLeftCorner.x > outputEast) {
outputEast = topLeftCorner.x;
}
if (topLeftCorner.x < outputWest) {
outputWest = topLeftCorner.x;
}
if (topRightCorner.y > outputNorth) {
outputNorth = topRightCorner.y;
}
if (topRightCorner.y < outputSouth) {
outputSouth = topRightCorner.y;
}
if (topRightCorner.x > outputEast) {
outputEast = topRightCorner.x;
}
if (topRightCorner.x < outputWest) {
outputWest = topRightCorner.x;
}
if (bottomLeftCorner.y > outputNorth) {
outputNorth = bottomLeftCorner.y;
}
if (bottomLeftCorner.y < outputSouth) {
outputSouth = bottomLeftCorner.y;
}
if (bottomLeftCorner.x > outputEast) {
outputEast = bottomLeftCorner.x;
}
if (bottomLeftCorner.x < outputWest) {
outputWest = bottomLeftCorner.x;
}
if (bottomRightCorner.y > outputNorth) {
outputNorth = bottomRightCorner.y;
}
if (bottomRightCorner.y < outputSouth) {
outputSouth = bottomRightCorner.y;
}
if (bottomRightCorner.x > outputEast) {
outputEast = bottomRightCorner.x;
}
if (bottomRightCorner.x < outputWest) {
outputWest = bottomRightCorner.x;
}
double nsRange = outputNorth - outputSouth;
double ewRange = outputEast - outputWest;
int nRows = (int) (nsRange / avgGridRes);
int nCols = (int) (ewRange / avgGridRes);
WhiteboxRaster output = new WhiteboxRaster(outputImageFile, outputNorth,
outputSouth, outputEast, outputWest, nRows, nCols, inputImage.getDataScale(),
inputImage.getDataType(), inputImage.getNoDataValue(), inputImage.getNoDataValue());
double outputX, outputY;
double inputX, inputY;
int inputCol, inputRow;
XYPoint point;
double z;
int oldProgress = -1;
int progress;
for (int row = 0; row < nRows; row++) {
for (int col = 0; col < nCols; col++) {
outputX = output.getXCoordinateFromColumn(col);
outputY = output.getYCoordinateFromRow(row);
// back transform them into image 2 coordinates.
point = getBackwardCoordinates(outputX, outputY);
inputX = point.x;
inputY = point.y;
inputCol = inputImage.getColumnFromXCoordinate(inputX);
inputRow = inputImage.getRowFromYCoordinate(inputY);
z = inputImage.getValue(inputRow, inputCol);
output.setValue(row, col, z);
}
if (cancelOp) {
cancelOperation();
return null;
}
progress = (int) (100f * row / (nRows - 1));
if (progress != oldProgress) {
setProgress(progress);
}
}
output.addMetadataEntry("Created by the "
+ "ImageRectification tool.");
output.addMetadataEntry("Created on " + new Date());
output.close();
returnData(outputImageFile);
return null;
} catch (Exception e) {
return null;
} finally {
isRunning = false;
}
}
/*
* Executed in event dispatching thread
*/
@Override
public void done() {
setProgress(0);
}
}
}