/** * 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; } } } }