Package com.lightcrafts.media.jai.opimage

Source Code of com.lightcrafts.media.jai.opimage.BinarizeOpImage

/*
* $RCSfile: BinarizeOpImage.java,v $
*
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* Use is subject to license terms.
*
* $Revision: 1.1 $
* $Date: 2005/02/11 04:56:15 $
* $State: Exp $
*/
package com.lightcrafts.media.jai.opimage;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.util.Map;
import com.lightcrafts.mediax.jai.ImageLayout;
import com.lightcrafts.mediax.jai.PointOpImage;
import com.lightcrafts.mediax.jai.PixelAccessor;
import com.lightcrafts.mediax.jai.PackedImageData;
import com.lightcrafts.mediax.jai.UnpackedImageData;
import com.lightcrafts.media.jai.util.JDKWorkarounds;
import com.lightcrafts.media.jai.util.ImageUtil;

/**
* An <code>OpImage</code> implementing the "Binarize" operation as
* described in <code>com.lightcrafts.mediax.jai.operator.BinarizeDescriptor</code>.
*
* <p>This <code>OpImage</code> maps all the pixels of an image
* whose value falls within a given range to a constant on a per-band basis.
* Each of the lower bound, upper bound, and constant arrays may have only
* one value in it. If that is the case, that value is used for all bands.
*
* @see com.lightcrafts.mediax.jai.operator.BinarizeDescriptor
* @see BinarizeCRIF
*
* @since version 1.1
*/
final class BinarizeOpImage extends PointOpImage {

    /**
     * Lookup table for ORing bytes of output.
     */
    private static byte[] byteTable = new byte[] {
        (byte)0x80, (byte)0x40, (byte)0x20, (byte)0x10,
        (byte)0x08, (byte)0x04, (byte)0x02, (byte)0x01,
    };

    /**
     *  bitsOn[j + (i<<3)]
     *  sets bits on from i to j
     */
    private static int[] bitsOn = null;

    /** The threshold. */
    private double threshold;

    /**
     * Constructor.
     *
     * @param source     The source image.
     * @param layout     The destination image layout.
     * @param threshold  The threshold value for binarization.
     */
    public BinarizeOpImage(RenderedImage source,
         Map config,
         ImageLayout layout,
         double threshold) {
        super(source, layoutHelper(source, layout, config), config, true);

        if(source.getSampleModel().getNumBands() != 1) {
      throw new IllegalArgumentException(JaiI18N.getString("BinarizeOpImage0"));
        }

  this.threshold = threshold;
    }

    // set the OpImage's SM to be MultiPixelPackedSampleModel
    private static ImageLayout layoutHelper(RenderedImage source,
                                            ImageLayout il,
                                            Map config) {

        ImageLayout layout = (il == null) ?
            new ImageLayout() : (ImageLayout)il.clone();

        SampleModel sm = layout.getSampleModel(source);
        if(!ImageUtil.isBinary(sm)) {
            sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
                                                 layout.getTileWidth(source),
                                                 layout.getTileHeight(source),
                                                 1);
            layout.setSampleModel(sm);
        }

        ColorModel cm = layout.getColorModel(null);
        if(cm == null ||
           !JDKWorkarounds.areCompatibleDataModels(sm, cm)) {
            layout.setColorModel(ImageUtil.getCompatibleColorModel(sm,
                                                                   config));
        }
          
        return layout;
    }


    /**
     * Map the pixels inside a specified rectangle whose value is within a
     * rang to a constant on a per-band basis.
     *
     * @param sources   Cobbled sources, guaranteed to provide all the
     *                  source data necessary for computing the rectangle.
     * @param dest      The tile containing the rectangle to be computed.
     * @param destRect  The rectangle within the tile to be computed.
     */
    protected void computeRect(Raster[] sources,
                               WritableRaster dest,
                               Rectangle destRect) {
        switch (sources[0].getSampleModel().getDataType()) {
        case DataBuffer.TYPE_BYTE:
       byteLoop(sources[0], dest, destRect);
       break;

        case DataBuffer.TYPE_SHORT:
       shortLoop(sources[0], dest, destRect);
       break;
        case DataBuffer.TYPE_USHORT:
       ushortLoop(sources[0], dest, destRect);
       break;
        case DataBuffer.TYPE_INT:
       intLoop(sources[0], dest, destRect);
       break;

        case DataBuffer.TYPE_FLOAT:
       floatLoop(sources[0], dest, destRect);
       break;
        case DataBuffer.TYPE_DOUBLE:
       doubleLoop(sources[0], dest, destRect);
       break;

        default:
      throw new RuntimeException(JaiI18N.getString("BinarizeOpImage1"));
        }
    }

    private void byteLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

        if(threshold <= 0.0D){
      // every bit is 1
      setTo1(dest, destRect);
      return;
  }else if (threshold > 255.0D){
      //every bit is zeros;
      return;
  }
 
  short thresholdI = (short)Math.ceil(threshold);
  // computation can be done in integer
  // even though threshold is of double type
  // int thresholdI = (int)Math.ceil(this.threshold);
  // or through a lookup table for byte case

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_BYTE, false);
  int srcOffset  = srcImD.bandOffsets[0];
  byte[] srcData = ((byte[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
               if((srcData[s]&0xFF) >= thresholdI) {
                   pid.data[offset + (b >> 3)] |= byteTable[b%8];
               }
     }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }


    // computation in short
    private void shortLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

        if(threshold <= Short.MIN_VALUE){
      // every bit is 1
      setTo1(dest, destRect);
      return;
  }else if (threshold > Short.MAX_VALUE){
      //every bit is zeros;
      return;
  }
  
  short thresholdS = (short)( Math.ceil(threshold));
  // computation can be done in integer
  // even though threshold is of double type
  // int thresholdI = (int)Math.ceil(this.threshold);
  // or through a lookup table for byte case

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_SHORT, false);
  int srcOffset  = srcImD.bandOffsets[0];
  short[] srcData = ((short[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
               if(srcData[s] >= thresholdS) {
                   pid.data[offset + (b >> 3)] |= byteTable[b%8];
               }
     }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }


    // computation in short
    private void ushortLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

        if(threshold <= 0.0D){
      // every bit is 1
      setTo1(dest, destRect);
      return;
  }else if (threshold > (double)(0xFFFF)){
      //every bit is zeros;
      return;
  }
  
  int thresholdI = (int)( Math.ceil(threshold));
  // computation can be done in integer
  // even though threshold is of double type
  // int thresholdI = (int)Math.ceil(this.threshold);
  // or through a lookup table for byte case

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_USHORT, false);
  int srcOffset  = srcImD.bandOffsets[0];
  short[] srcData = ((short[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
               if((srcData[s]&0xFFFF) >= thresholdI) {
                   pid.data[offset + (b >> 3)] |= byteTable[b%8];
               }
     }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }



    private void intLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

        if(threshold <= Integer.MIN_VALUE){
      // every bit is 1
      setTo1(dest, destRect);
      return;
  }else if (threshold > (double)Integer.MAX_VALUE){
      //every bit is zeros;
      return;
  }
  
  // computation can be done in integer
  // even though threshold is of double type
  int thresholdI = (int)Math.ceil(this.threshold);

  // computation can be done in integer
  // even though threshold is of double type
  // int thresholdI = (int)Math.ceil(this.threshold);

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_INT, false);
  int srcOffset  = srcImD.bandOffsets[0];
  int[] srcData = ((int[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
               if(srcData[s] >= threshold) {
                   pid.data[offset + (b >> 3)] |= byteTable[b%8];
               }
           }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }


    // computation in float
    private void floatLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_FLOAT, false);
  int srcOffset  = srcImD.bandOffsets[0];
  float[] srcData = ((float[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
       if (srcData[s]>threshold) {
                 pid.data[offset + (b >> 3)] |= byteTable[b%8];
             }
     }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }

    // computation in double
    private void doubleLoop(Raster source,
        WritableRaster dest,
        Rectangle destRect){

  Rectangle srcRect = mapDestRect(destRect,0); // should be identical to destRect

        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;
        PixelAccessor   srcPa  = new PixelAccessor(source.getSampleModel(), null);

        UnpackedImageData srcImD = srcPa.getPixels(source, srcRect, DataBuffer.TYPE_DOUBLE, false);
  int srcOffset  = srcImD.bandOffsets[0];
  double[] srcData = ((double[][])srcImD.data)[0];
  int pixelStride= srcImD.pixelStride;

  int ind0 = pid.bitOffset;
  for(int h = 0; h < destRect.height; h++){
     int indE = ind0 + destRect.width;
     for(int b = ind0, s = srcOffset; b < indE; b++, s += pixelStride){
       if (srcData[s]>threshold) {
                 pid.data[offset + (b >> 3)] |= byteTable[b%8];
             }
     }
     offset += pid.lineStride;
     srcOffset += srcImD.lineStride;
  }
  pa.setPackedPixels(pid);
    }

    // set all bits in a rectangular region to be 1
    // need to be sure that paddings not changing
    private void setTo1(Raster dest, Rectangle destRect){
        initBitsOn();
        PixelAccessor   pa  = new PixelAccessor(dest.getSampleModel(), null);
        PackedImageData pid = pa.getPackedPixels(dest, destRect, true, false);
  int offset = pid.offset;

  for(int h = 0; h < destRect.height; h++){
     int ind0 = pid.bitOffset;
     int indE = ind0 + destRect.width - 1;
     if (indE < 8){
        // the entire row in data[offset]
        pid.data[offset] = (byte)(pid.data[offset] | bitsOn[indE]); // (0<<3) + indE
     }else{
            //1st byte
        pid.data[offset] = (byte)(pid.data[offset] | bitsOn[7]); // (0<<3) + 7
        //middle bytes
        for(int b = offset + 1; b <= offset +  (indE-7)/8; b++){
     pid.data[b] = (byte)(0xff);
        }
        //last byte

        int remBits = indE % 8;
        if(remBits % 8 != 7){
      indE = offset + indE/8;
      pid.data[indE] = (byte)(pid.data[indE] | bitsOn[remBits]); // (0<<3)+remBits
        }
     }
     offset += pid.lineStride;
  }
  pa.setPackedPixels(pid);
    }

    // setting bits i to j to 1;
    //  i <= j
    private static synchronized void initBitsOn() {

       if(bitsOn != null)
    return;
     
       bitsOn = new int[64];
       for(int i = 0; i < 8; i++){
    for(int j = i; j< 8; j++){
       int bi = (0x00ff) >> i;
       int bj = (0x00ff) << (7-j);
       bitsOn[j + (i<<3)] = bi & bj;
    }
       }
    }
}
TOP

Related Classes of com.lightcrafts.media.jai.opimage.BinarizeOpImage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.