-
Notifications
You must be signed in to change notification settings - Fork 37
Warp Operation
This new version of the JAI Warp Operation is provided for supporting ROI and No Data values when the Warp operation is performed. Below are described the various step for achieving this goal.
WORKFLOW:
- extension of the JAI WarpOpImage class;
- creation of various subclasses, each of them implementing the Warp operation for a specific interpolation type;
- creation of the descriptor and the RenderedImageFactory associated to the Warp operation;
- testing of all the classes.
The classes used by the Warp operation are:
- WarpOpImage.java : this class is a super class which takes and prepares the input parameters for the subclasses. It is an extension of the JAI WarpOpImage.java class.
- WarpDescriptor.java : this class describes the input parameters to use for the Warp operation.
- WarpRIF.java : RenderedImageFactory class associated to the warp operation. This class is called when the JAI.create("WarpNoData",...) method is used.
- WarpNearestOpImage.java : Subclass of the WarpOpImage class optimized for the nearest-neighbor interpolation.
- WarpBilinearOpImage.java : Subclass of the WarpOpImage class optimized for the bilinear interpolation.
- WarpBicubicOpImage.java : Subclass of the WarpOpImage class optimized for the bicubic interpolation.
- WarpGeneralOpImage.java : Subclass of the WarpOpImage class to use when the interpolation object is none of the 3 defined above.
- JaiI18N.java : Utility class for loading definitions from a property file.
Warp is an operation which can cause distorsion on the input pixels positions and is defined in Java by the Warp.java class. Any instance of this class must be able to apply the defined transformation on a point, line, Rectangle.
WarpOpImage.java class is an abstract class used for the inizialization and containing some accessor methods.
WarpDescriptor.java and WarpRIF.java are two fundamental class for calculating an operation with JAI. The first class defines the operation parameters and also their default values. With its static method create(...) it is possible to set the input parameters and source so that the descriptor internally groups these parameters into a ParameterBlock object and passes it to the JAI.create(...) method. This method then searches for the RenderedImageFactory associated to the Warp operation, WarpRIF, and requests a new instance of the WarpOpImage class. The RenderedImageFactory takes the ParameterBlock object and searches for the subclass of the WarpOpImage associated to the interpolation object provided. Note that interpolation must be always defined.
For executing the Warp operation, the user can also directly call the JAI.create(...) method with the associated ParameterBlock object but must set "WarpNoData" as operation name.
The other four subclasses of WarpOpImage are quite similar between them, because they only override the computeRect() method of their super class and calculate the warp for each destination image tile. The calculation steps are:
- backward mapping from the destination pixel positions to the source pixel positions with the Warp object;
- Selection of the pixel values related to the source positions;
- If ROI or No Data are present, check if the source pixel values are outside of the ROI or are No Data;
- Pixel interpolation;
- Saving of the final value into the associated destination pixel position.
A simple pseudo-code for better understanding the Warp operation:
// numBand = image band number
// minYpositionIndex, minXpositionIndex = destination image minimum index values on the source array
// destHeight, destWidth = destination image dimensions
// src, dest = source and destination images
// roi = possible ROI object
// noDataRange = possible range of source no data
// warp = warp transformation object
// interp = interpolation object
// x,y = source index positions
for(int b = 0; b < numBand; b++){
for(int j = minYpositionIndex; j < destHeight; j++){
double[] sourcePixelPositions = warp.warpRect(0,j,destWidth,1)
for(int i = minXpositionIndex; i < destWidth; i++){
//Source pixel positions
x = round(sourcePixelPositions[i]);
y = round(sourcePixelPositions[i+1]);
//NoData and ROI check
int pixel = src(x,y,b);
if(roi.contains(pixel)){
dest(i,j,b) = background;
} else if(noDataRange.contains(pixel)){
dest(i,j,b) = background;
}else{
dest(i,j,b) = interp.interpolate(x,y,b)
}
}
}
}
For testing the Warp operation a few test-classes are present:
- TestWarp.java
- NearestWarpTest.java
- BilinearWarpTest.java
- BicubicWarpTest.java
- GeneralWarpTest.java
- ComparisonTest.java
The first class is an utility class which provides methods for calculating the warp operation on various kind of images with and without ROI and NoData. The other classes extend TestWarp class and use its methods for creating and testing various images with different data type.
The 2nd, 3rd, 4th and 5th test classes do the same tests, but each one of them uses a different interpolation method. The tests executed are:
- test on images without using ROI or No Data Range;
- test on images using ROI but without No Data Range;
- test on images without using ROI but using No Data Range;
- test on images using ROI and No Data Range.
The user can see the result of one of the four tests by setting the following JVM parameters:
- -DJAI.Ext.Interactive to true(default false);
- -DJAI.Ext.TestSelection to 0(No ROI nor NoData, default), 2(only ROI), 4(only NoData), 5(ROI and NoData).
The last test-class compares the computation time between the old and the new Warp operation. This test is executed by repeatedly calling the getTiles() method for every cycle and saving the calculation time. At the end of every cycle the JAI TileCache is flushed so that all the image tiles must be recalculated. The average, maximum and minimum computation times are not saved for all the iterations, because the first N iterations are not considered due to the Java HotSpot compilation. The number of the iterations to consider and not can be set by passing respectively these 2 Integer parameters to the JVM: JAI.Ext.BenchmarkCycles and JAI.Ext.NotBenchmarkCycles. For selecting which one of the 2 descriptors must be tested, the JAI.Ext.OldDescriptor JVM parameter must be set to true or false(true for the old descriptor and false for the new one); for using ROI the JAI.Ext.ROIUsed parameter must be set to true, the same for NoData with the JAI.Ext.RangeUsed parameter. If the native acceleration should be used, then the JAI.Ext.Acceleration JVM parameter must be set to true. The interpolation type can be set by assigning 0(nearest),1(bilinear),2(bicubic) to the JAI.Ext.InterpSelector parameter. The choice of the image data type is defined by the parameter JAI.Ext.TestSelection (0 for byte images, 1 Ushort, 2 Short, 3 Integer, 4 Float, 5 Double). The statistics are print to the screen at the end of the process.