예제 #1
0
  /**
   * Creates a SampleOpImage with the given ParameterBlock if the SampleOpImage can handle the
   * particular ParameterBlock.
   */
  @Override
  public RenderedImage create(ParameterBlock paramBlock, RenderingHints renderHints) {
    PlanarImage source1 = (PlanarImage) paramBlock.getRenderedSource(0);
    if (source1 == null) {
      return null;
    }
    ROIShape shape = (ROIShape) paramBlock.getObjectParameter(0);
    if (shape == null) {
      return source1;
    }

    TiledImage image;
    if (ImageUtil.isBinary(source1.getSampleModel())) {
      image =
          new TiledImage(
              source1.getMinX(),
              source1.getMinY(),
              source1.getWidth(),
              source1.getHeight(),
              source1.getTileGridXOffset(),
              source1.getTileGridYOffset(),
              LayoutUtil.createBinarySampelModel(),
              LayoutUtil.createBinaryIndexColorModel());
    } else {
      // rgb cannot be null or have less than one value
      Byte[] rgb = (Byte[]) paramBlock.getObjectParameter(1);
      int nbands = source1.getSampleModel().getNumBands();
      if (rgb.length != nbands) {
        Byte fillVal = rgb[0];
        rgb = new Byte[nbands];
        Arrays.fill(rgb, fillVal);
      }

      image = ImageFiler.getEmptyTiledImage(rgb, source1.getWidth(), source1.getHeight());
    }

    image.set(source1, shape);
    return image;
  }
예제 #2
0
  /*
   * Create a Raster from a JPEG-compressed data stream.
   */
  private Raster getJPEGTile(int tx, int ty, int subType, byte[] data) {
    int tableIndex = (subType >> 24) & 0x000000ff;
    ;
    boolean colorConversion = (subType & 0x00ff0000) != 0;
    JPEGDecodeParam decodeParam = null;
    if (tableIndex != 0) {
      decodeParam = getJPEGDecodeParam(tableIndex);
    }

    ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
    JPEGImageDecoder decoder =
        decodeParam == null
            ? JPEGCodec.createJPEGDecoder(byteStream)
            : JPEGCodec.createJPEGDecoder(byteStream, decodeParam);

    Raster raster = null;
    try {
      raster = decoder.decodeAsRaster().createTranslatedChild(tx, ty);
    } catch (Exception e) {

      ImagingListener listener = ImageUtil.getImagingListener(renderHints);
      listener.errorOccurred(
          JaiI18N.getString("IIPResolutionOpImage3"), new ImagingException(e), this, false);
      /*
                  String msg = JaiI18N.getString("IIPResolutionOpImage3")+" "+
                      e.getMessage();
                  throw new RuntimeException(msg);
      */
    }
    closeStream(byteStream);

    if (colorSpaceType == CS_NIFRGB && colorConversion) {
      YCbCrToNIFRGB(raster);
    }

    return raster;
  }
예제 #3
0
  // This method is similar to the testBandMerge method but it tests the ExtendedBandMergeOpImage
  // class
  private void testExtendedBandMerge(RenderedImage[] sources, boolean noDataUsed, boolean roiUsed) {
    // Optional No Data Range used
    Range[] noData;
    // Source image data type
    int dataType = sources[0].getSampleModel().getDataType();
    // If no Data are present, the No Data Range associated is used
    if (noDataUsed) {

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          noData = noDataByte;
          break;
        case DataBuffer.TYPE_USHORT:
          noData = noDataUShort;
          break;
        case DataBuffer.TYPE_SHORT:
          noData = noDataShort;
          break;
        case DataBuffer.TYPE_INT:
          noData = noDataInt;
          break;
        case DataBuffer.TYPE_FLOAT:
          noData = noDataFloat;
          break;
        case DataBuffer.TYPE_DOUBLE:
          noData = noDataDouble;
          break;
        default:
          throw new IllegalArgumentException("Wrong data type");
      }
    } else {
      noData = null;
    }

    // ROI to use
    ROI roi = null;
    if (roiUsed) {
      roi = roiData;
    }

    // New array ofr the transformed source images
    RenderedOp[] translated = new RenderedOp[sources.length];

    List<AffineTransform> transform = new ArrayList<AffineTransform>();

    for (int i = 0; i < sources.length; i++) {
      // Translation coefficients
      int xTrans = (int) (Math.random() * 10);
      int yTrans = (int) (Math.random() * 10);
      // Translation operation
      AffineTransform tr = AffineTransform.getTranslateInstance(xTrans, yTrans);
      // Addition to the transformations list
      transform.add(tr);
      // Translation of the image
      translated[i] =
          TranslateDescriptor.create(sources[i], (float) xTrans, (float) yTrans, null, null);
    }
    // Definition of the final image dimensions
    ImageLayout layout = new ImageLayout();
    layout.setMinX(sources[0].getMinX());
    layout.setMinY(sources[0].getMinY());
    layout.setWidth(sources[0].getWidth());
    layout.setHeight(sources[0].getHeight());

    RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);

    // BandMerge operation
    RenderedOp merged =
        BandMergeDescriptor.create(noData, destNoData, hints, transform, roi, translated);

    Assert.assertNotNull(merged.getTiles());
    // Check if the bands number is the same
    assertEquals(BAND_NUMBER, merged.getNumBands());
    // Upper-Left tile indexes
    int minTileX = merged.getMinTileX();
    int minTileY = merged.getMinTileY();
    // Raster object
    Raster upperLeftTile = merged.getTile(minTileX, minTileY);
    // Tile bounds
    int minX = upperLeftTile.getMinX();
    int minY = upperLeftTile.getMinY();
    int maxX = upperLeftTile.getWidth() + minX;
    int maxY = upperLeftTile.getHeight() + minY;

    // Source corners
    final int dstMinX = merged.getMinX();
    final int dstMinY = merged.getMinY();
    final int dstMaxX = merged.getMaxX();
    final int dstMaxY = merged.getMaxY();

    Point2D ptDst = new Point2D.Double(0, 0);
    Point2D ptSrc = new Point2D.Double(0, 0);

    // Cycle on all the tile Bands
    for (int b = 0; b < BAND_NUMBER; b++) {
      RandomIter iter = RandomIterFactory.create(translated[b], null);

      // Source corners
      final int srcMinX = translated[b].getMinX();
      final int srcMinY = translated[b].getMinY();
      final int srcMaxX = translated[b].getMaxX();
      final int srcMaxY = translated[b].getMaxY();

      // Cycle on the y-axis
      for (int x = minX; x < maxX; x++) {
        // Cycle on the x-axis
        for (int y = minY; y < maxY; y++) {
          // Calculated value
          double value = upperLeftTile.getSampleDouble(x, y, b);
          // If the tile pixels are outside the image bounds, then no data is set.
          if (x < dstMinX || x >= dstMaxX || y < dstMinY || y >= dstMaxY) {
            value = destNoData;
          }

          // Set the x,y destination pixel location
          ptDst.setLocation(x, y);
          // Map destination pixel to source pixel
          transform.get(b).transform(ptDst, ptSrc);
          // Source pixel indexes
          int srcX = round(ptSrc.getX());
          int srcY = round(ptSrc.getY());

          double valueOld = destNoData;

          // Check if the pixel is inside the source bounds
          if (!(srcX < srcMinX || srcX >= srcMaxX || srcY < srcMinY || srcY >= srcMaxY)) {
            // Old band value
            valueOld = iter.getSampleDouble(srcX, srcY, 0);
          }

          // ROI CHECK
          boolean contained = true;
          if (roiUsed) {
            if (!roi.contains(x, y)) {
              contained = false;
              // Comparison if the final value is not inside a ROI
              assertEquals(value, destNoData, TOLERANCE);
            }
          }

          if (contained) {
            // If no Data are present, no data check is performed
            if (noDataUsed) {
              switch (dataType) {
                case DataBuffer.TYPE_BYTE:
                  byte sampleB = ImageUtil.clampRoundByte(value);
                  byte sampleBOld = ImageUtil.clampRoundByte(valueOld);
                  if (noData[0].contains(sampleBOld)) {
                    assertEquals(sampleB, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleB, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_USHORT:
                  short sampleUS = ImageUtil.clampRoundUShort(value);
                  short sampleUSOld = ImageUtil.clampRoundUShort(valueOld);
                  if (noData[0].contains(sampleUSOld)) {
                    assertEquals(sampleUS, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleUS, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_SHORT:
                  short sampleS = ImageUtil.clampRoundShort(value);
                  short sampleSOld = ImageUtil.clampRoundShort(valueOld);
                  if (noData[0].contains(sampleSOld)) {
                    assertEquals(sampleS, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleS, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_INT:
                  int sampleI = ImageUtil.clampRoundInt(value);
                  int sampleIOld = ImageUtil.clampRoundInt(valueOld);
                  if (noData[0].contains(sampleIOld)) {
                    assertEquals(sampleI, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleI, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_FLOAT:
                  float sampleF = ImageUtil.clampFloat(value);
                  float sampleFOld = ImageUtil.clampFloat(valueOld);
                  if (noData[0].contains(sampleFOld)) {
                    assertEquals(sampleF, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleF, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_DOUBLE:
                  if (noData[0].contains(valueOld)) {
                    assertEquals(value, destNoData, TOLERANCE);
                  } else {
                    assertEquals(value, valueOld, TOLERANCE);
                  }
                  break;
                default:
                  throw new IllegalArgumentException("Wrong data type");
              }
            } else {
              // Else a simple value comparison is done
              assertEquals(value, valueOld, TOLERANCE);
            }
          }
        }
      }
    }
    // Disposal of the output image
    merged.dispose();
  }
예제 #4
0
  private void testBandMerge(RenderedImage[] sources, boolean noDataUsed, boolean roiUsed) {
    // Optional No Data Range used
    Range[] noData;
    // Source image data type
    int dataType = sources[0].getSampleModel().getDataType();
    // If no Data are present, the No Data Range associated is used
    if (noDataUsed) {

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          noData = noDataByte;
          break;
        case DataBuffer.TYPE_USHORT:
          noData = noDataUShort;
          break;
        case DataBuffer.TYPE_SHORT:
          noData = noDataShort;
          break;
        case DataBuffer.TYPE_INT:
          noData = noDataInt;
          break;
        case DataBuffer.TYPE_FLOAT:
          noData = noDataFloat;
          break;
        case DataBuffer.TYPE_DOUBLE:
          noData = noDataDouble;
          break;
        default:
          throw new IllegalArgumentException("Wrong data type");
      }
    } else {
      noData = null;
    }

    // ROI to use
    ROI roi = null;
    if (roiUsed) {
      roi = roiData;
    }

    // BandMerge operation
    RenderedOp merged = BandMergeDescriptor.create(noData, destNoData, null, null, roi, sources);
    // Check if the bands number is the same
    assertEquals(BAND_NUMBER, merged.getNumBands());
    // Upper-Left tile indexes
    int minTileX = merged.getMinTileX();
    int minTileY = merged.getMinTileY();
    // Raster object
    Raster upperLeftTile = merged.getTile(minTileX, minTileY);
    // Tile bounds
    int minX = upperLeftTile.getMinX();
    int minY = upperLeftTile.getMinY();
    int maxX = upperLeftTile.getWidth() + minX;
    int maxY = upperLeftTile.getHeight() + minY;
    // Cycle on all the tile Bands
    for (int b = 0; b < BAND_NUMBER; b++) {
      // Selection of the source raster associated with the band
      Raster bandRaster = sources[b].getTile(minTileX, minTileY);
      // Cycle on the y-axis
      for (int x = minX; x < maxX; x++) {
        // Cycle on the x-axis
        for (int y = minY; y < maxY; y++) {
          // Calculated value
          double value = upperLeftTile.getSampleDouble(x, y, b);
          // Old band value
          double valueOld = bandRaster.getSampleDouble(x, y, 0);

          // ROI CHECK
          boolean contained = true;
          if (roiUsed) {
            if (!roi.contains(x, y)) {
              contained = false;
              // Comparison if the final value is not inside a ROI
              assertEquals(value, destNoData, TOLERANCE);
            }
          }

          if (contained) {
            // If no Data are present, no data check is performed
            if (noDataUsed) {
              switch (dataType) {
                case DataBuffer.TYPE_BYTE:
                  byte sampleB = ImageUtil.clampRoundByte(value);
                  byte sampleBOld = ImageUtil.clampRoundByte(valueOld);
                  if (noData[0].contains(sampleBOld)) {
                    assertEquals(sampleB, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleB, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_USHORT:
                  short sampleUS = ImageUtil.clampRoundUShort(value);
                  short sampleUSOld = ImageUtil.clampRoundUShort(valueOld);
                  if (noData[0].contains(sampleUSOld)) {
                    assertEquals(sampleUS, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleUS, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_SHORT:
                  short sampleS = ImageUtil.clampRoundShort(value);
                  short sampleSOld = ImageUtil.clampRoundShort(valueOld);
                  if (noData[0].contains(sampleSOld)) {
                    assertEquals(sampleS, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleS, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_INT:
                  int sampleI = ImageUtil.clampRoundInt(value);
                  int sampleIOld = ImageUtil.clampRoundInt(valueOld);
                  if (noData[0].contains(sampleIOld)) {
                    assertEquals(sampleI, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleI, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_FLOAT:
                  float sampleF = ImageUtil.clampFloat(value);
                  float sampleFOld = ImageUtil.clampFloat(valueOld);
                  if (noData[0].contains(sampleFOld)) {
                    assertEquals(sampleF, destNoData, TOLERANCE);
                  } else {
                    assertEquals(sampleF, valueOld, TOLERANCE);
                  }
                  break;
                case DataBuffer.TYPE_DOUBLE:
                  if (noData[0].contains(valueOld)) {
                    assertEquals(value, destNoData, TOLERANCE);
                  } else {
                    assertEquals(value, valueOld, TOLERANCE);
                  }
                  break;
                default:
                  throw new IllegalArgumentException("Wrong data type");
              }
            } else {
              // Else a simple value comparison is done
              assertEquals(value, valueOld, TOLERANCE);
            }
          }
        }
      }
    }
    // Disposal of the output image
    merged.dispose();
  }
예제 #5
0
  public void testRescale(
      RenderedImage source,
      boolean roiUsed,
      boolean noDataUsed,
      boolean useRoiAccessor,
      TestSelection select) {

    // The precalculated roi is used, if selected by the related boolean.
    ROI roiData;

    if (roiUsed) {
      roiData = roi;
    } else {
      roiData = null;
    }

    // The precalculated NoData Range is used, if selected by the related boolean.
    Range noDataRange;
    // Image data type
    int dataType = source.getSampleModel().getDataType();

    if (noDataUsed) {

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          noDataRange = noDataByte;
          break;
        case DataBuffer.TYPE_USHORT:
          noDataRange = noDataUShort;
          break;
        case DataBuffer.TYPE_SHORT:
          noDataRange = noDataShort;
          break;
        case DataBuffer.TYPE_INT:
          noDataRange = noDataInt;
          break;
        case DataBuffer.TYPE_FLOAT:
          noDataRange = noDataFloat;
          break;
        case DataBuffer.TYPE_DOUBLE:
          noDataRange = noDataDouble;
          break;
        default:
          throw new IllegalArgumentException("Wrong data type");
      }
    } else {
      noDataRange = null;
    }

    // Rescale operation
    PlanarImage rescaled =
        RescaleDescriptor.create(
            source, scales, offsets, roiData, noDataRange, useRoiAccessor, destNoData, null);

    // Display Image
    if (INTERACTIVE && TEST_SELECTOR == select.getType()) {
      RenderedImageBrowser.showChain(rescaled, false, roiUsed);
      try {
        System.in.read();
      } catch (IOException e) {
        e.printStackTrace();
      }

    } else {
      // Calculation of all the image tiles
      rescaled.getTiles();
    }

    // Rescale control on the first band
    int tileMinX = rescaled.getMinTileX();
    int tileMinY = rescaled.getMinTileY();
    // Selection of the source and destination first tile
    Raster tileDest = rescaled.getTile(tileMinX, tileMinY);
    Raster tileSource = source.getTile(tileMinX, tileMinY);

    int tileMinXpix = tileDest.getMinX();
    int tileMinYpix = tileDest.getMinY();

    int tileMaxXpix = tileDest.getWidth() + tileMinXpix;
    int tileMaxYpix = tileDest.getHeight() + tileMinYpix;

    double scaleFactor = scales[0];
    double offset = offsets[0];
    // loop through the tile pixels
    for (int i = tileMinXpix; i < tileMaxXpix; i++) {
      for (int j = tileMinYpix; j < tileMaxYpix; j++) {

        switch (dataType) {
          case DataBuffer.TYPE_BYTE:
            // selection of the rescaled pixel
            byte destValueB = (byte) tileDest.getSample(i, j, 0);
            // rescale operation on the source pixel
            int srcValueB = tileSource.getSample(i, j, 0) & 0xFF;
            byte calculationB = ImageUtil.clampRoundByte(srcValueB * scaleFactor + offset);
            // comparison
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains((byte) srcValueB)) {
                assertEquals(calculationB, destValueB);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationB, destValueB);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains((byte) srcValueB)) {
                assertEquals(calculationB, destValueB);
              }
            } else {
              assertEquals(calculationB, destValueB);
            }
            break;
          case DataBuffer.TYPE_USHORT:
            short destValueU = (short) tileDest.getSample(i, j, 0);
            int srcValueU = tileSource.getSample(i, j, 0) & 0xFFFF;
            short calculationU = ImageUtil.clampRoundUShort(srcValueU * scaleFactor + offset);
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains((short) srcValueU)) {
                assertEquals(calculationU, destValueU);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationU, destValueU);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains((short) srcValueU)) {
                assertEquals(calculationU, destValueU);
              }
            } else {
              assertEquals(calculationU, destValueU);
            }
            break;
          case DataBuffer.TYPE_SHORT:
            short destValueS = (short) tileDest.getSample(i, j, 0);
            short srcValueS = (short) tileSource.getSample(i, j, 0);
            short calculationS = ImageUtil.clampRoundShort(srcValueS * scaleFactor + offset);
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains(srcValueS)) {
                assertEquals(calculationS, destValueS);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationS, destValueS);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains(srcValueS)) {
                assertEquals(calculationS, destValueS);
              }
            } else {
              assertEquals(calculationS, destValueS);
            }
            break;
          case DataBuffer.TYPE_INT:
            int destValueI = tileDest.getSample(i, j, 0);
            int srcValueI = tileSource.getSample(i, j, 0);
            int calculationI = ImageUtil.clampRoundInt(srcValueI * scaleFactor + offset);
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains(srcValueI)) {
                assertEquals(calculationI, destValueI);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationI, destValueI);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains(srcValueI)) {
                assertEquals(calculationI, destValueI);
              }
            } else {
              assertEquals(calculationI, destValueI);
            }
            break;
          case DataBuffer.TYPE_FLOAT:
            float destValueF = tileDest.getSampleFloat(i, j, 0);
            float srcValueF = tileSource.getSampleFloat(i, j, 0);
            float calculationF = (float) ((srcValueF * scaleFactor) + offset);
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains(srcValueF)) {
                assertEquals(calculationF, destValueF, TOLERANCE);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationF, destValueF, TOLERANCE);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains(srcValueF)) {
                assertEquals(calculationF, destValueF, TOLERANCE);
              }
            } else {
              assertEquals(calculationF, destValueF, TOLERANCE);
            }
            break;
          case DataBuffer.TYPE_DOUBLE:
            double destValueD = tileDest.getSampleDouble(i, j, 0);
            double srcValueD = tileSource.getSampleDouble(i, j, 0);
            double calculationD = ((srcValueD * scaleFactor) + offset);
            if (roiUsed && noDataUsed) {
              if (roiBounds.contains(i, j) && !noDataRange.contains(srcValueD)) {
                assertEquals(calculationD, destValueD, TOLERANCE);
              }
            } else if (roiUsed) {
              if (roiBounds.contains(i, j)) {
                assertEquals(calculationD, destValueD, TOLERANCE);
              }
            } else if (noDataUsed) {
              if (!noDataRange.contains(srcValueD)) {
                assertEquals(calculationD, destValueD, TOLERANCE);
              }
            } else {
              assertEquals(calculationD, destValueD, TOLERANCE);
            }
            break;
          default:
            throw new IllegalArgumentException("Wrong data type");
        }
      }
    }
  }
예제 #6
0
  private void testType(RenderedImage src, boolean nodataUsed, boolean roiUsed) {
    // Optional No Data Range used
    Range noData;
    // Source image data type
    int dataType = src.getSampleModel().getDataType();
    // If no Data are present, the No Data Range associated is used
    if (nodataUsed) {

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          noData = noDataByte;
          break;
        case DataBuffer.TYPE_USHORT:
          noData = noDataUShort;
          break;
        case DataBuffer.TYPE_SHORT:
          noData = noDataShort;
          break;
        case DataBuffer.TYPE_INT:
          noData = noDataInt;
          break;
        case DataBuffer.TYPE_FLOAT:
          noData = noDataFloat;
          break;
        case DataBuffer.TYPE_DOUBLE:
          noData = noDataDouble;
          break;
        default:
          throw new IllegalArgumentException("Wrong data type");
      }
    } else {
      noData = null;
    }

    ROI roi;

    if (roiUsed) {
      roi = roiObject;
    } else {
      roi = null;
    }

    // BandCombined result
    RenderedOp combined =
        BandCombineDescriptor.create(src, matrix, roi, noData, destinationNoData, null);

    int tileWidth = combined.getTileWidth();
    int tileHeight = combined.getTileHeight();
    int minTileX = combined.getMinTileX();
    int minTileY = combined.getMinTileY();
    int numXTiles = combined.getNumXTiles();
    int numYTiles = combined.getNumYTiles();
    int maxTileX = minTileX + numXTiles;
    int maxTileY = minTileY + numYTiles;
    // Ensure same size
    assertEquals(combined.getWidth(), src.getWidth());
    assertEquals(combined.getHeight(), src.getHeight());
    assertEquals(combined.getMinX(), src.getMinX());
    assertEquals(combined.getMinY(), src.getMinY());
    assertEquals(minTileX, src.getMinTileX());
    assertEquals(minTileY, src.getMinTileY());
    assertEquals(numXTiles, src.getNumXTiles());
    assertEquals(numYTiles, src.getNumYTiles());
    assertEquals(tileWidth, src.getTileWidth());
    assertEquals(tileHeight, src.getTileHeight());

    int srcBands = src.getSampleModel().getNumBands();
    int dstBands = combined.getNumBands();

    // Ensure a correct band size
    assertEquals(dstBands, matrix.length);

    // Check on all the pixels if they have been calculate correctly
    for (int tileX = minTileX; tileX < maxTileX; tileX++) {
      for (int tileY = minTileY; tileY < maxTileY; tileY++) {
        Raster tile = combined.getTile(tileX, tileY);
        Raster srcTile = src.getTile(tileX, tileY);

        int minX = tile.getMinX();
        int minY = tile.getMinY();
        int maxX = minX + tileWidth - 1;
        int maxY = minY + tileHeight - 1;

        for (int x = minX; x <= maxX; x++) {
          for (int y = minY; y <= maxY; y++) {

            boolean isValidRoi = !roiUsed || (roiUsed && roiObject.contains(x, y));

            if (isValidRoi) {
              for (int b = 0; b < dstBands; b++) {
                // Getting the result
                double result = tile.getSampleDouble(x, y, b);

                // Calculating the expected result from sources
                boolean valid = false;
                double calculated = 0;

                for (int i = 0; i < srcBands; i++) {
                  double sample = srcTile.getSampleDouble(x, y, i);
                  boolean isValidData =
                      !nodataUsed || (nodataUsed && !noDataDouble.contains(sample));
                  valid |= isValidData;
                  if (isValidData) {
                    switch (dataType) {
                      case DataBuffer.TYPE_BYTE:
                        calculated += ((int) sample & 0xFF) * matrix[b][i];
                        break;
                      case DataBuffer.TYPE_USHORT:
                        calculated += ((int) sample & 0xFFFF) * matrix[b][i];
                        break;
                      case DataBuffer.TYPE_SHORT:
                      case DataBuffer.TYPE_INT:
                      case DataBuffer.TYPE_FLOAT:
                      case DataBuffer.TYPE_DOUBLE:
                        calculated += sample * matrix[b][i];
                        break;
                      default:
                        break;
                    }
                  }
                }

                if (valid) {
                  calculated += matrix[b][srcBands];
                  switch (dataType) {
                    case DataBuffer.TYPE_BYTE:
                      calculated = ImageUtil.clampRoundByte(calculated);
                      result = ImageUtil.clampRoundByte(result);
                      break;
                    case DataBuffer.TYPE_USHORT:
                      calculated = ImageUtil.clampRoundUShort(calculated);
                      result = ImageUtil.clampRoundUShort(result);
                      break;
                    case DataBuffer.TYPE_SHORT:
                      calculated = ImageUtil.clampRoundShort(calculated);
                      result = ImageUtil.clampRoundShort(result);
                      break;
                    case DataBuffer.TYPE_INT:
                      calculated = ImageUtil.clampRoundInt(calculated);
                      result = ImageUtil.clampRoundInt(result);
                      break;
                    case DataBuffer.TYPE_FLOAT:
                      calculated = (float) calculated;
                      calculated = (float) result;
                      break;
                    case DataBuffer.TYPE_DOUBLE:
                      break;
                    default:
                      break;
                  }
                  assertEquals(result, calculated, TOLERANCE);
                } else {
                  assertEquals(result, destNoData, TOLERANCE);
                }
              }
            } else {
              for (int b = 0; b < dstBands; b++) {
                assertEquals(tile.getSampleDouble(x, y, b), destNoData, TOLERANCE);
              }
            }
          }
        }
      }
    }

    // Disposal of the output image
    combined.dispose();
  }