use of ini.trakem2.display.MipMapImage in project TrakEM2 by trakem2.
the class ExportARGB method makeFlatImageARGBFromMipMaps.
/**
* Returns nonsense or throws an Exception if mipmaps are not available.
* Limited to 2GB arrays for the final image.
*
* @param patches
* @param roi
* @param backgroundValue
* @param scale
* @return
*/
public static final Pair<ColorProcessor, ByteProcessor> makeFlatImageARGBFromMipMaps(final List<Patch> patches, final Rectangle roi, final double backgroundValue, final double scale) {
final int width = (int) (roi.width * scale);
final int height = (int) (roi.height * scale);
// Process the three channels separately in order to use proper alpha composition
final ColorProcessor target = new ColorProcessor(width, height);
target.setInterpolationMethod(ImageProcessor.BILINEAR);
final ByteProcessor targetMask = new ByteProcessor(width, height);
targetMask.setInterpolationMethod(ImageProcessor.BILINEAR);
final Loader loader = patches.get(0).getProject().getLoader();
for (final Patch patch : patches) {
// MipMap image, already including any coordinate transforms and the alpha mask (if any), by definition.
final MipMapImage mipMap = loader.fetchImage(patch, scale);
// / DEBUG: is there an alpha channel at all?
// new ij.ImagePlus("alpha of " + patch.getTitle(), new ByteProcessor( mipMap.image.getWidth(null), mipMap.image.getHeight(null), new ColorProcessor( mipMap.image ).getChannel( 4 ))).show();
// Yes, there is, even though the mipmap images have the alpha pre-multiplied
// Work-around strange bug that makes mipmap-loaded images paint with 7-bit depth instead of 8-bit depth
final BufferedImage bi = new BufferedImage(mipMap.image.getWidth(null), mipMap.image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = bi.createGraphics();
g2d.drawImage(mipMap.image, 0, 0, null);
g2d.dispose();
final int[] pix = extractARGBIntArray(bi);
bi.flush();
// DEBUG: does the BufferedImage have the alpha channel?
// {
// final byte[] aa = new byte[pix.length];
// for (int i=0; i<aa.length; ++i) aa[i] = (byte)((pix[i] & 0xff000000) >> 24);
// new ij.ImagePlus("alpha of BI of " + patch.getTitle(), new ByteProcessor(bi.getWidth(), bi.getHeight(), aa)).show();
// }
// YES: the alpha, containing the outside too. All fine.
final ByteProcessor alpha;
final ColorProcessor rgb = new ColorProcessor(bi.getWidth(), bi.getHeight(), pix);
if (patch.hasAlphaChannel()) {
// The mipMap has the alpha channel in it, even if the alpha is pre-multiplied as well onto the images.
final byte[] a = new byte[pix.length];
for (int i = 0; i < a.length; ++i) {
a[i] = (byte) ((pix[i] & 0xff000000) >> 24);
}
alpha = new ByteProcessor(bi.getWidth(), bi.getHeight(), a);
} else {
alpha = new ByteProcessor(bi.getWidth(), bi.getHeight());
Arrays.fill((byte[]) alpha.getPixels(), (byte) 255);
}
// The affine to apply to the MipMap.image
final AffineTransform atc = new AffineTransform();
atc.scale(scale, scale);
atc.translate(-roi.x, -roi.y);
final AffineTransform at = new AffineTransform();
at.preConcatenate(atc);
at.concatenate(patch.getAffineTransform());
at.scale(mipMap.scaleX, mipMap.scaleY);
final AffineModel2D aff = new AffineModel2D();
aff.set(at);
final CoordinateTransformMesh mesh = new CoordinateTransformMesh(aff, patch.getMeshResolution(), bi.getWidth(), bi.getHeight());
final TransformMeshMappingWithMasks<CoordinateTransformMesh> mapping = new TransformMeshMappingWithMasks<CoordinateTransformMesh>(mesh);
// no interpolation
alpha.setInterpolationMethod(ImageProcessor.NEAREST_NEIGHBOR);
rgb.setInterpolationMethod(ImageProcessor.BILINEAR);
mapping.map(rgb, alpha, target, targetMask);
}
return new Pair<ColorProcessor, ByteProcessor>(target, targetMask);
}
Aggregations