/** * Initializes this operator and sets the one and only target product. * * <p>The target product can be either defined by a field of type {@link Product} annotated with * the {@link TargetProduct TargetProduct} annotation or by calling {@link #setTargetProduct} * method. * * <p>The framework calls this method after it has created this operator. Any client code that * must be performed before computation of tile data should be placed here. * * @throws OperatorException If an error occurs during operator initialisation. * @see #getTargetProduct() */ @Override public void initialize() throws OperatorException { try { absRoot = AbstractMetadata.getAbstractedMetadata(sourceProduct); getSourceImageDimension(); getMetadata(); computeSensorPositionsAndVelocities(); createTargetProduct(); if (externalDEMFile == null) { DEMFactory.checkIfDEMInstalled(demName); } DEMFactory.validateDEM(demName, sourceProduct); if (reGridMethod) { computeDEMTraversalSampleInterval(); } else if (orbitMethod) { meta = new SLCImage(absRoot); jOrbit = new Orbit(absRoot, 3); } } catch (Throwable e) { OperatorUtils.catchOperatorException(getId(), e); } }
/** * Compute initial cluster centers for clusters in all 3 categories: vol, dbl, suf. * * @param srcBandList the input bands * @param tileRectangles Array of rectangles for all source tiles of the image * @param op the operator */ private void computeInitialTerrainClusterCenters( final double[][] fdd, final java.util.List<ClusterInfo> pvCenterList, final java.util.List<ClusterInfo> pdCenterList, final java.util.List<ClusterInfo> psCenterList, final PolBandUtils.PolSourceBand srcBandList, final Rectangle[] tileRectangles, final PolarimetricClassificationOp op) { try { // Step 1. Create initial 30 clusters in each of the 3 categories (vol, dbl, surf). // System.out.println("Step 1"); createInitialClusters(fdd, srcBandList, tileRectangles, op); // Step 2. Compute cluster centers for all 90 clusters in the 3 categories // System.out.println("Step 2"); getClusterCenters(pvCenterList, pdCenterList, psCenterList, srcBandList, tileRectangles, op); // Step 3. Merge small clusters in each category until user specified total number of clusters // is reached // System.out.println("Step 3"); mergeInitialClusters(pvCenterList, pdCenterList, psCenterList); } catch (Throwable e) { OperatorUtils.catchOperatorException(op.getId() + " computeInitialClusterCenters ", e); } }
/** * Compute centers for all numClasses clusters * * @param srcBandList the input bands * @param op the operator */ private synchronized void computeTerrainClusterCenters( final PolBandUtils.PolSourceBand srcBandList, final PolarimetricClassificationOp op) { if (clusterCentersComputed) { return; } mask = new byte[srcHeight][srcWidth]; final double[][] fdd = new double[srcHeight][srcWidth]; final java.util.List<ClusterInfo> pvCenterList = new ArrayList<>(numInitialClusters); final java.util.List<ClusterInfo> pdCenterList = new ArrayList<>(numInitialClusters); final java.util.List<ClusterInfo> psCenterList = new ArrayList<>(numInitialClusters); maxClusterSize = 2 * srcHeight * srcWidth / numFinalClasses; final Dimension tileSize = new Dimension(256, 256); final Rectangle[] tileRectangles = OperatorUtils.getAllTileRectangles(op.getSourceProduct(), tileSize, 0); computeInitialTerrainClusterCenters( fdd, pvCenterList, pdCenterList, psCenterList, srcBandList, tileRectangles, op); computeFinalTerrainClusterCenters( fdd, pvCenterList, pdCenterList, psCenterList, srcBandList, tileRectangles, op); clusterCentersComputed = true; }
/** * Retrieve required data from Abstracted Metadata * * @throws Exception if metadata not found */ private void getMetadata() throws Exception { srgrFlag = AbstractMetadata.getAttributeBoolean(absRoot, AbstractMetadata.srgr_flag); wavelength = SARUtils.getRadarFrequency(absRoot); rangeSpacing = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.range_spacing); firstLineUTC = absRoot.getAttributeUTC(AbstractMetadata.first_line_time).getMJD(); // in days lastLineUTC = absRoot.getAttributeUTC(AbstractMetadata.last_line_time).getMJD(); // in days lineTimeInterval = absRoot.getAttributeDouble(AbstractMetadata.line_time_interval) / Constants.secondsInDay; // s to day orbitStateVectors = AbstractMetadata.getOrbitStateVectors(absRoot); if (srgrFlag) { srgrConvParams = AbstractMetadata.getSRGRCoefficients(absRoot); } else { nearEdgeSlantRange = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.slant_range_to_first_pixel); } final TiePointGrid incidenceAngle = OperatorUtils.getIncidenceAngle(sourceProduct); nearRangeOnLeft = SARGeocoding.isNearRangeOnLeft(incidenceAngle, sourceImageWidth); }
private double fillHole(final int xx, final int yy, final double[][] srcArray) throws Exception { try { final int h = srcArray.length; final int w = srcArray[0].length; double vU = noDataValue, vD = noDataValue, vL = noDataValue, vR = noDataValue; int yU = -1, yD = -1, xL = -1, xR = -1; for (int y = yy; y >= 0; y--) { if (srcArray[y][xx] != noDataValue) { vU = srcArray[y][xx]; yU = y; break; } } for (int y = yy; y < h; y++) { if (srcArray[y][xx] != noDataValue) { if (vU != noDataValue) { vD = srcArray[y][xx]; yD = y; break; } else { vU = srcArray[y][xx]; yU = y; } } } for (int x = xx; x >= 0; x--) { if (srcArray[yy][x] != noDataValue) { vL = srcArray[yy][x]; xL = x; break; } } for (int x = xx; x < w; x++) { if (srcArray[yy][x] != noDataValue) { if (vL != noDataValue) { vR = srcArray[yy][x]; xR = x; break; } else { vL = srcArray[yy][x]; xL = x; } } } if (vU != noDataValue && vD != noDataValue && vL != noDataValue && vR != noDataValue) { final double vY = vU + (vD - vU) * (yy - yU) / (yD - yU); final double vX = vL + (vR - vL) * (xx - xL) / (xR - xL); return 0.5 * (vY + vX); } else if (vU != noDataValue && vD != noDataValue) { return vU + (vD - vU) * (yy - yU) / (yD - yU); } else if (vL != noDataValue && vR != noDataValue) { return vL + (vR - vL) * (xx - xL) / (xR - xL); } else if (vL != noDataValue) { return vL; } else if (vR != noDataValue) { return vR; } else if (vU != noDataValue) { return vU; } else if (vD != noDataValue) { return vD; } } catch (Exception e) { OperatorUtils.catchOperatorException(getId(), e); } return noDataValue; }
/** * Called by the framework in order to compute the stack of tiles for the given target bands. * * <p>The default implementation throws a runtime exception with the message "not implemented". * * @param targetTiles The current tiles to be computed for each target band. * @param targetRectangle The area in pixel coordinates to be computed (same for all rasters in * <code>targetRasters</code>). * @param pm A progress monitor which should be used to determine computation cancelation * requests. * @throws OperatorException if an error occurs during computation of the target rasters. */ @Override public void computeTileStack( Map<Band, Tile> targetTiles, Rectangle targetRectangle, ProgressMonitor pm) throws OperatorException { final int x0 = targetRectangle.x; final int y0 = targetRectangle.y; final int w = targetRectangle.width; final int h = targetRectangle.height; // System.out.println("x0 = " + x0 + ", y0 = " + y0 + ", w = " + w + ", h = " + h); double[] tileOverlapPercentage = {0.0, 0.0}; try { if (!isElevationModelAvailable) { getElevationModel(); } computeTileOverlapPercentage(x0, y0, w, h, tileOverlapPercentage); // System.out.println("x0 = " + x0 + ", y0 = " + y0 + ", w = " + w + ", h = " + h + // ", tileOverlapPercentageMin = " + tileOverlapPercentage[0] + // ", tileOverlapPercentageMax = " + tileOverlapPercentage[1]); } catch (Exception e) { throw new OperatorException(e); } final Tile latTile = targetTiles.get(targetProduct.getBand(LATITUDE_BAND_NAME)); final Tile lonTile = targetTiles.get(targetProduct.getBand(LONGITUDE_BAND_NAME)); final ProductData latData = latTile.getDataBuffer(); final ProductData lonData = lonTile.getDataBuffer(); final double[][] latArray = new double[h][w]; final double[][] lonArray = new double[h][w]; for (int r = 0; r < h; r++) { Arrays.fill(latArray[r], noDataValue); Arrays.fill(lonArray[r], noDataValue); } final int ymin = Math.max(y0 - (int) (tileSize * tileOverlapPercentage[1]), 0); final int ymax = y0 + h + (int) (tileSize * Math.abs(tileOverlapPercentage[0])); final int xmax = x0 + w; final PositionData posData = new PositionData(); final GeoPos geoPos = new GeoPos(); try { if (reGridMethod) { final double[] latLonMinMax = new double[4]; computeImageGeoBoundary(x0, xmax, ymin, ymax, latLonMinMax); final double latMin = latLonMinMax[0]; final double latMax = latLonMinMax[1]; final double lonMin = latLonMinMax[2]; final double lonMax = latLonMinMax[3]; final int nLat = (int) ((latMax - latMin) / delLat) + 1; final int nLon = (int) ((lonMax - lonMin) / delLon) + 1; final double[][] tileDEM = new double[nLat + 1][nLon + 1]; double alt; for (int i = 0; i < nLat; i++) { final double lat = latMin + i * delLat; for (int j = 0; j < nLon; j++) { double lon = lonMin + j * delLon; if (lon >= 180.0) { lon -= 360.0; } geoPos.setLocation(lat, lon); alt = dem.getElevation(geoPos); if (alt == demNoDataValue) { continue; } tileDEM[i][j] = alt; if (!getPosition(lat, lon, alt, x0, y0, w, h, posData)) { continue; } final int ri = (int) Math.round(posData.rangeIndex); final int ai = (int) Math.round(posData.azimuthIndex); if (ri < x0 || ri >= x0 + w || ai < y0 || ai >= y0 + h) { continue; } latArray[ai - y0][ri - x0] = lat; lonArray[ai - y0][ri - x0] = lon; } } } else { final double[][] localDEM = new double[ymax - ymin + 2][w + 2]; final TileGeoreferencing tileGeoRef = new TileGeoreferencing(sourceProduct, x0, ymin, w, ymax - ymin); final boolean valid = DEMFactory.getLocalDEM( dem, demNoDataValue, demResamplingMethod, tileGeoRef, x0, ymin, w, ymax - ymin, sourceProduct, true, localDEM); if (!valid) { return; } for (int y = ymin; y < ymax; y++) { final int yy = y - ymin; for (int x = x0; x < xmax; x++) { final int xx = x - x0; double alt = localDEM[yy + 1][xx + 1]; if (alt == demNoDataValue) { continue; } tileGeoRef.getGeoPos(x, y, geoPos); if (!geoPos.isValid()) { continue; } double lat = geoPos.lat; double lon = geoPos.lon; if (lon >= 180.0) { lon -= 360.0; } if (orbitMethod) { double[] latlon = jOrbit.lp2ell(new Point(x + 0.5, y + 0.5), meta); lat = latlon[0] * Constants.RTOD; lon = latlon[1] * Constants.RTOD; alt = dem.getElevation(new GeoPos(lat, lon)); } if (!getPosition(lat, lon, alt, x0, y0, w, h, posData)) { continue; } final int ri = (int) Math.round(posData.rangeIndex); final int ai = (int) Math.round(posData.azimuthIndex); if (ri < x0 || ri >= x0 + w || ai < y0 || ai >= y0 + h) { continue; } latArray[ai - y0][ri - x0] = lat; lonArray[ai - y0][ri - x0] = lon; } } } // todo should replace the following code with Delaunay interpolation final TileIndex trgIndex = new TileIndex(latTile); for (int y = y0; y < y0 + h; y++) { final int yy = y - y0; trgIndex.calculateStride(y); for (int x = x0; x < x0 + w; x++) { final int xx = x - x0; final int index = trgIndex.getIndex(x); if (latArray[yy][xx] == noDataValue) { latData.setElemDoubleAt(index, fillHole(xx, yy, latArray)); } else { latData.setElemDoubleAt(index, latArray[yy][xx]); } if (lonArray[yy][xx] == noDataValue) { lonData.setElemDoubleAt(index, fillHole(xx, yy, lonArray)); } else { lonData.setElemDoubleAt(index, lonArray[yy][xx]); } } } } catch (Throwable e) { OperatorUtils.catchOperatorException(getId(), e); } }
/** * Compute final cluster centers for all clusters using K-mean clustering method * * @param srcBandList the input bands * @param tileRectangles Array of rectangles for all source tiles of the image * @param op the operator */ private void computeFinalTerrainClusterCenters( final double[][] fdd, final java.util.List<ClusterInfo> pvCenterList, final java.util.List<ClusterInfo> pdCenterList, final java.util.List<ClusterInfo> psCenterList, final PolBandUtils.PolSourceBand srcBandList, final Rectangle[] tileRectangles, final PolarimetricClassificationOp op) { boolean endIteration = false; final StatusProgressMonitor status = new StatusProgressMonitor(StatusProgressMonitor.TYPE.SUBTASK); status.beginTask("Computing Final Cluster Centres... ", tileRectangles.length * maxIterations); final int pvNumClusters = pvCenterList.size(); final int pdNumClusters = pdCenterList.size(); final int psNumClusters = psCenterList.size(); final int maxNumClusters = Math.max(pvNumClusters, Math.max(pdNumClusters, psNumClusters)); final int[][] clusterCounter = new int[3][maxNumClusters]; final ThreadManager threadManager = new ThreadManager(); try { for (int it = 0; (it < maxIterations && !endIteration); ++it) { // System.out.println("Iteration: " + it); // final long startTime = System.nanoTime(); // final long endTime; final double[][][] pvSumRe = new double[pvNumClusters][3][3]; final double[][][] pvSumIm = new double[pvNumClusters][3][3]; final double[][][] pdSumRe = new double[pdNumClusters][3][3]; final double[][][] pdSumIm = new double[pdNumClusters][3][3]; final double[][][] psSumRe = new double[psNumClusters][3][3]; final double[][][] psSumIm = new double[psNumClusters][3][3]; java.util.Arrays.fill(clusterCounter[0], 0); java.util.Arrays.fill(clusterCounter[1], 0); java.util.Arrays.fill(clusterCounter[2], 0); for (final Rectangle rectangle : tileRectangles) { final Thread worker = new Thread() { final Tile[] sourceTiles = new Tile[srcBandList.srcBands.length]; final ProductData[] dataBuffers = new ProductData[srcBandList.srcBands.length]; final double[][] Tr = new double[3][3]; final double[][] Ti = new double[3][3]; @Override public void run() { op.checkIfCancelled(); final int x0 = rectangle.x; final int y0 = rectangle.y; final int w = rectangle.width; final int h = rectangle.height; final int xMax = x0 + w; final int yMax = y0 + h; final Rectangle sourceRectangle = getSourceRectangle(x0, y0, w, h); for (int i = 0; i < sourceTiles.length; ++i) { sourceTiles[i] = op.getSourceTile(srcBandList.srcBands[i], sourceRectangle); dataBuffers[i] = sourceTiles[i].getDataBuffer(); } final TileIndex srcIndex = new TileIndex(sourceTiles[0]); for (int y = y0; y < yMax; ++y) { for (int x = x0; x < xMax; ++x) { PolOpUtils.getMeanCoherencyMatrix( x, y, halfWindowSizeX, halfWindowSizeY, srcWidth, srcHeight, sourceProductType, srcIndex, dataBuffers, Tr, Ti); int clusterIdx; synchronized (clusterCounter) { if (mask[y][x] < -64) { // pv clusterIdx = findClosestCluster(Tr, Ti, pvCenterList); computeSummationOfT3(clusterIdx + 1, Tr, Ti, pvSumRe, pvSumIm); clusterCounter[0][clusterIdx] += 1; mask[y][x] = (byte) (-128 + clusterIdx); } else if (mask[y][x] < 0) { // pd clusterIdx = findClosestCluster(Tr, Ti, pdCenterList); computeSummationOfT3(clusterIdx + 1, Tr, Ti, pdSumRe, pdSumIm); clusterCounter[1][clusterIdx] += 1; mask[y][x] = (byte) (-64 + clusterIdx); } else if (mask[y][x] < 64) { // ps clusterIdx = findClosestCluster(Tr, Ti, psCenterList); computeSummationOfT3(clusterIdx + 1, Tr, Ti, psSumRe, psSumIm); clusterCounter[2][clusterIdx] += 1; mask[y][x] = (byte) clusterIdx; } else { // mixed java.util.List<ClusterInfo> allCenterList = new ArrayList<>(); allCenterList.addAll(pvCenterList); allCenterList.addAll(pdCenterList); allCenterList.addAll(psCenterList); clusterIdx = findClosestCluster(Tr, Ti, allCenterList); if (clusterIdx >= pvNumClusters + pdNumClusters) { // ps clusterIdx -= pvNumClusters + pdNumClusters; computeSummationOfT3(clusterIdx + 1, Tr, Ti, psSumRe, psSumIm); clusterCounter[2][clusterIdx] += 1; mask[y][x] = (byte) clusterIdx; } else if (clusterIdx >= pvNumClusters) { // pd clusterIdx -= pvNumClusters; computeSummationOfT3(clusterIdx + 1, Tr, Ti, pdSumRe, pdSumIm); clusterCounter[1][clusterIdx] += 1; mask[y][x] = (byte) (-64 + clusterIdx); } else { // pv computeSummationOfT3(clusterIdx + 1, Tr, Ti, pvSumRe, pvSumIm); clusterCounter[0][clusterIdx] += 1; mask[y][x] = (byte) (-128 + clusterIdx); } } } } } } }; threadManager.add(worker); status.worked(1); } threadManager.finish(); /* endTime = System.nanoTime(); final long duration = endTime - startTime; System.out.println("duration = " + duration); */ updateClusterCenter(pvCenterList, clusterCounter[0], pvSumRe, pvSumIm); updateClusterCenter(pdCenterList, clusterCounter[1], pdSumRe, pdSumIm); updateClusterCenter(psCenterList, clusterCounter[2], psSumRe, psSumIm); } /* System.out.println("# of clusters in Pv: " + pvNumClusters); System.out.print("Pixels in each Pv cluster: "); for (int i = 0; i < pvNumClusters; i++) { System.out.print(clusterCounter[0][i] + ", "); } System.out.println(); System.out.println("# of clusters in Pd: " + pdNumClusters); System.out.print("Pixels in each Pd cluster: "); for (int i = 0; i < pdNumClusters; i++) { System.out.print(clusterCounter[1][i] + ", "); } System.out.println(); System.out.println("# of clusters in Ps: " + psNumClusters); System.out.print("Pixels in each Ps cluster: "); for (int i = 0; i < psNumClusters; i++) { System.out.print(clusterCounter[2][i] + ", "); } System.out.println(); */ // todo the average cluster power should be used in colour selection for each cluster, not // used now // compute average power for each cluster final double[] pvAvgClusterPower = new double[pvNumClusters]; final double[] pdAvgClusterPower = new double[pdNumClusters]; final double[] psAvgClusterPower = new double[psNumClusters]; int clusterIdx = -1; for (int y = 0; y < srcHeight; y++) { for (int x = 0; x < srcWidth; x++) { if (mask[y][x] < -64) { // pv clusterIdx = mask[y][x] + 128; pvAvgClusterPower[clusterIdx] += fdd[y][x]; } else if (mask[y][x] < 0) { // pd clusterIdx = mask[y][x] + 64; pdAvgClusterPower[clusterIdx] += fdd[y][x]; } else { // ps clusterIdx = mask[y][x]; psAvgClusterPower[clusterIdx] += fdd[y][x]; } } } for (int c = 0; c < pvNumClusters; c++) { pvAvgClusterPower[c] /= clusterCounter[0][c]; } for (int c = 0; c < pdNumClusters; c++) { pdAvgClusterPower[c] /= clusterCounter[1][c]; } for (int c = 0; c < psNumClusters; c++) { psAvgClusterPower[c] /= clusterCounter[2][c]; } // map cluster index to colour index, colour index ranges for the 3 categories are given by // surf: [0,29], vol: [30, 59] and dbl: [60,89], currently the clusters are evenly distributed // in the // colour range pvColourIndexMap = new int[pvNumClusters]; pdColourIndexMap = new int[pdNumClusters]; psColourIndexMap = new int[psNumClusters]; for (int c = 0; c < pvNumClusters; c++) { pvColourIndexMap[c] = numInitialClusters + getColourIndex(c, pvAvgClusterPower, numInitialClusters) + 1; } for (int c = 0; c < pdNumClusters; c++) { pdColourIndexMap[c] = 2 * numInitialClusters + getColourIndex(c, pdAvgClusterPower, numInitialClusters) + 1; } for (int c = 0; c < psNumClusters; c++) { psColourIndexMap[c] = getColourIndex(c, psAvgClusterPower, numInitialClusters) + 1; } } catch (Throwable e) { OperatorUtils.catchOperatorException(op.getId() + " computeInitialClusterCenters ", e); } finally { status.done(); } }
/** * Compute the centers of the 90 clusters in the 3 categories. * * @param srcBandList the input bands * @param tileRectangles Array of rectangles for all source tiles of the image * @param op the operator */ private void getClusterCenters( final java.util.List<ClusterInfo> pvCenterList, final java.util.List<ClusterInfo> pdCenterList, final java.util.List<ClusterInfo> psCenterList, final PolBandUtils.PolSourceBand srcBandList, final Rectangle[] tileRectangles, final PolarimetricClassificationOp op) { final StatusProgressMonitor status = new StatusProgressMonitor(StatusProgressMonitor.TYPE.SUBTASK); status.beginTask("Computing Initial Cluster Centres... ", tileRectangles.length); final ThreadManager threadManager = new ThreadManager(); final double[][][] pvSumRe = new double[numInitialClusters][3][3]; final double[][][] pvSumIm = new double[numInitialClusters][3][3]; final double[][][] pdSumRe = new double[numInitialClusters][3][3]; final double[][][] pdSumIm = new double[numInitialClusters][3][3]; final double[][][] psSumRe = new double[numInitialClusters][3][3]; final double[][][] psSumIm = new double[numInitialClusters][3][3]; // counter for the number of pixels in each cluster in the 3 categories: vol, dbl, suf final int[][] clusterCounter = new int[3][numInitialClusters]; try { for (final Rectangle rectangle : tileRectangles) { op.checkIfCancelled(); final Thread worker = new Thread() { final Tile[] sourceTiles = new Tile[srcBandList.srcBands.length]; final ProductData[] dataBuffers = new ProductData[srcBandList.srcBands.length]; final double[][] Sr = new double[2][2]; final double[][] Si = new double[2][2]; final double[][] Tr = new double[3][3]; final double[][] Ti = new double[3][3]; @Override public void run() { final int x0 = rectangle.x; final int y0 = rectangle.y; final int w = rectangle.width; final int h = rectangle.height; final int xMax = x0 + w; final int yMax = y0 + h; // System.out.println("x0 = " + x0 + ", y0 = " + y0 + ", w = " + w + ", h = " + h); for (int i = 0; i < sourceTiles.length; ++i) { sourceTiles[i] = op.getSourceTile(srcBandList.srcBands[i], rectangle); dataBuffers[i] = sourceTiles[i].getDataBuffer(); } final TileIndex srcIndex = new TileIndex(sourceTiles[0]); for (int y = y0; y < yMax; ++y) { srcIndex.calculateStride(y); for (int x = x0; x < xMax; ++x) { PolOpUtils.getT3(srcIndex.getIndex(x), sourceProductType, dataBuffers, Tr, Ti); synchronized (clusterCounter) { int clusterIdx; if (mask[y][x] < -64) { // pv clusterIdx = mask[y][x] + 128; computeSummationOfT3(clusterIdx + 1, Tr, Ti, pvSumRe, pvSumIm); clusterCounter[0][clusterIdx]++; } else if (mask[y][x] < 0) { // pd clusterIdx = mask[y][x] + 64; computeSummationOfT3(clusterIdx + 1, Tr, Ti, pdSumRe, pdSumIm); clusterCounter[1][clusterIdx]++; } else if (mask[y][x] < 64) { // ps clusterIdx = mask[y][x]; computeSummationOfT3(clusterIdx + 1, Tr, Ti, psSumRe, psSumIm); clusterCounter[2][clusterIdx]++; } } } } } }; threadManager.add(worker); status.worked(1); } threadManager.finish(); } catch (Throwable e) { OperatorUtils.catchOperatorException(op.getId() + " getClusterCenters ", e); } finally { status.done(); } // compute centers for all 90 clusters for (int c = 0; c < numInitialClusters; c++) { double[][] centerRe = new double[3][3]; double[][] centerIm = new double[3][3]; if (clusterCounter[0][c] > 0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { centerRe[i][j] = pvSumRe[c][i][j] / clusterCounter[0][c]; centerIm[i][j] = pvSumIm[c][i][j] / clusterCounter[0][c]; } } ClusterInfo clusterCenter = new ClusterInfo(); clusterCenter.setClusterCenter(c, centerRe, centerIm, clusterCounter[0][c]); pvCenterList.add(clusterCenter); } if (clusterCounter[1][c] > 0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { centerRe[i][j] = pdSumRe[c][i][j] / clusterCounter[1][c]; centerIm[i][j] = pdSumIm[c][i][j] / clusterCounter[1][c]; } } ClusterInfo clusterCenter = new ClusterInfo(); clusterCenter.setClusterCenter(c, centerRe, centerIm, clusterCounter[1][c]); pdCenterList.add(clusterCenter); } if (clusterCounter[2][c] > 0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { centerRe[i][j] = psSumRe[c][i][j] / clusterCounter[2][c]; centerIm[i][j] = psSumIm[c][i][j] / clusterCounter[2][c]; } } ClusterInfo clusterCenter = new ClusterInfo(); clusterCenter.setClusterCenter(c, centerRe, centerIm, clusterCounter[2][c]); psCenterList.add(clusterCenter); } } }
/** * Create 30 initial clusters in each of the 3 categories (vol, dbl and surf). The pixels are * first classified into 4 categories (vol, dbl, urf and mixed) based on its Freeman-Durder * decomposition result. Then pixels in each category (not include mixed) are grouped into 30 * clusters based on their power values. * * @param srcBandList the input bands * @param tileRectangles Array of rectangles for all source tiles of the image * @param op the operator */ private void createInitialClusters( final double[][] fdd, final PolBandUtils.PolSourceBand srcBandList, final Rectangle[] tileRectangles, final PolarimetricClassificationOp op) { // Here mask[][] is used in recording the category index for each pixel with -128 for vol, -64 // for dbl, // 0 for surf and 64 for mixed. Later mask[][] will be used in recording for each pixel the // cluster index // in each category. [-128, -63] are for clusters in vol category, [-64, -1] are for clusters in // dbl // category and [0, 63] are for clusters in surf category. // // fdd[][] is used in recording the dominant power of the Freeman-Durden decomposition result // for each // pixel. final StatusProgressMonitor status = new StatusProgressMonitor(StatusProgressMonitor.TYPE.SUBTASK); status.beginTask("Creating Initial Clusters... ", tileRectangles.length); final int[] counter = new int[4]; // number of pixels in each of the 4 categories: vol, dbl, suf, mix final ThreadManager threadManager = new ThreadManager(); final double[] pv = new double[srcHeight * srcWidth]; final double[] pd = new double[srcHeight * srcWidth]; final double[] ps = new double[srcHeight * srcWidth]; try { for (final Rectangle rectangle : tileRectangles) { op.checkIfCancelled(); final Thread worker = new Thread() { final Tile[] sourceTiles = new Tile[srcBandList.srcBands.length]; final ProductData[] dataBuffers = new ProductData[srcBandList.srcBands.length]; final double[][] Cr = new double[3][3]; final double[][] Ci = new double[3][3]; @Override public void run() { final int x0 = rectangle.x; final int y0 = rectangle.y; final int w = rectangle.width; final int h = rectangle.height; final int xMax = x0 + w; final int yMax = y0 + h; // System.out.println("x0 = " + x0 + ", y0 = " + y0 + ", w = " + w + ", h = " + h); final Rectangle sourceRectangle = getSourceRectangle(x0, y0, w, h); for (int i = 0; i < sourceTiles.length; ++i) { sourceTiles[i] = op.getSourceTile(srcBandList.srcBands[i], sourceRectangle); dataBuffers[i] = sourceTiles[i].getDataBuffer(); } for (int y = y0; y < yMax; ++y) { for (int x = x0; x < xMax; ++x) { PolOpUtils.getMeanCovarianceMatrix( x, y, halfWindowSizeX, halfWindowSizeY, sourceProductType, sourceTiles, dataBuffers, Cr, Ci); final FreemanDurden.FDD data = FreemanDurden.getFreemanDurdenDecomposition(Cr, Ci); synchronized (counter) { if (!Double.isNaN(data.pv) && !Double.isNaN(data.pd) && !Double.isNaN(data.ps)) { Categories cat = getCategory(data.pv, data.pd, data.ps, mixedCategoryThreshold); if (cat == Categories.vol) { mask[y][x] = -128; fdd[y][x] = data.pv; pv[counter[0]] = data.pv; counter[0] += 1; } else if (cat == Categories.dbl) { mask[y][x] = -64; fdd[y][x] = data.pd; pd[counter[1]] = data.pd; counter[1] += 1; } else if (cat == Categories.suf) { mask[y][x] = 0; fdd[y][x] = data.ps; ps[counter[2]] = data.ps; counter[2] += 1; } else { // cat == Categories.mix mask[y][x] = 64; fdd[y][x] = (data.pv + data.pd + data.ps) / 3.0; counter[3] += 1; } } } } } } }; threadManager.add(worker); status.worked(1); } threadManager.finish(); } catch (Throwable e) { OperatorUtils.catchOperatorException(op.getId() + " createInitialClusters ", e); } finally { status.done(); } // for each category, compute 29 thresholds which will be used later in dividing each category // into 30 small // clusters with roughly equal number of pixels based on the pixel values. final int pvClusterSize = counter[0] / numInitialClusters; final int pdClusterSize = counter[1] / numInitialClusters; final int psClusterSize = counter[2] / numInitialClusters; if (pvClusterSize > 0) { Arrays.sort(pv, 0, counter[0] - 1); } if (pdClusterSize > 0) { Arrays.sort(pd, 0, counter[1] - 1); } if (psClusterSize > 0) { Arrays.sort(ps, 0, counter[2] - 1); } final double[] pvThreshold = new double[numInitialClusters - 1]; final double[] pdThreshold = new double[numInitialClusters - 1]; final double[] psThreshold = new double[numInitialClusters - 1]; for (int i = 0; i < numInitialClusters - 1; i++) { pvThreshold[i] = pv[(i + 1) * pvClusterSize]; pdThreshold[i] = pd[(i + 1) * pdClusterSize]; psThreshold[i] = ps[(i + 1) * psClusterSize]; } // classify pixels into 30 clusters within each category, record number of pixels in each // cluster int clusterIdx = -1; for (int y = 0; y < srcHeight; y++) { for (int x = 0; x < srcWidth; x++) { if (mask[y][x] == -128) { clusterIdx = computePixelClusterIdx(fdd[y][x], pvThreshold, numInitialClusters); mask[y][x] += clusterIdx; } else if (mask[y][x] == -64) { clusterIdx = computePixelClusterIdx(fdd[y][x], pdThreshold, numInitialClusters); mask[y][x] += clusterIdx; } else if (mask[y][x] == 0) { clusterIdx = computePixelClusterIdx(fdd[y][x], psThreshold, numInitialClusters); mask[y][x] += clusterIdx; } } } }