All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.batik.ext.awt.image.rendered.MorphologyOp Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */
package org.apache.batik.ext.awt.image.rendered;

import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.RasterOp;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;

import org.apache.batik.ext.awt.image.GraphicsUtil;

/**
 * This class provides an implementation for the SVG
 * feMorphology filter, as defined in Chapter 15, section 20
 * of the SVG specification.
 *
 * @author Sheng Pei
 * @version $Id: MorphologyOp.java 1733416 2016-03-03 07:07:13Z gadams $
 */
public class MorphologyOp implements BufferedImageOp, RasterOp {
    /**
     * The radius of the operation on X axis
     */
    private int radiusX;
    /**
     * The radius of the operation on Y axis
     */
    private int radiusY;
    /*
     * Determine whether to do the dilation or erosion operation.
     * Will do dilation when it's true and erosion when it's false.
     */
    private boolean doDilation;

    /*
     * rangeX is 2*radiusX+1, which is the width of the Kernel
     */
    private final int rangeX;

    /*
     * rangeY is 2*radiusY+1, which is the height of the Kernel
     */
    private final int rangeY;

    /*
     * sRGB ColorSpace instance used for compatibility checking
     */
    private final ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);

    /*
     * Linear RGB ColorSpace instance used for compatibility checking
     */
    private final ColorSpace lRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);

    /**
     * @param radiusX defines the radius of filter operation on X-axis. Should not be negative.
     *        A value of zero will disable the effect of the operation on X-axis, as described
     *        in the SVG specification.
     * @param radiusY defines the radius of filter operation on Y-axis. Should not be negative.
     *        A value of zero will disable the effect of the operation on Y-axis, as described
     *        in the SVG specification.
     * @param doDilation defines whether to do dilation or erosion operation. Will do dilation
     *        when the value is true, erosion when false.
     */
    public MorphologyOp (int radiusX, int radiusY, boolean doDilation){
        if (radiusX<=0 || radiusY<=0){
            throw new IllegalArgumentException( "The radius of X-axis or Y-axis should not be Zero or Negatives." );
        }
        else {
            this.radiusX = radiusX;
            this.radiusY = radiusY;
            this.doDilation = doDilation;
            rangeX = 2*radiusX + 1;
            rangeY = 2*radiusY + 1;
        }
    }

    public Rectangle2D getBounds2D(Raster src){
        checkCompatible(src.getSampleModel());
        return new Rectangle(src.getMinX(), src.getMinY(), src.getWidth(), src.getHeight());
    }

    public Rectangle2D getBounds2D(BufferedImage src){
        return new Rectangle(0, 0, src.getWidth(), src.getHeight());
    }

    public Point2D getPoint2D(Point2D srcPt, Point2D destPt){
        // This operation does not affect pixel location
        if(destPt==null)
            destPt = new Point2D.Float();
        destPt.setLocation(srcPt.getX(), srcPt.getY());
        return destPt;
    }

    private void checkCompatible(ColorModel colorModel,
                                 SampleModel sampleModel){
        ColorSpace cs = colorModel.getColorSpace();

        // Check that model is sRGB or linear RGB
        if((!cs .equals (sRGB)) && (!cs .equals( lRGB)))
            throw new IllegalArgumentException("Expected CS_sRGB or CS_LINEAR_RGB color model");

        // Check ColorModel is of type DirectColorModel
        if(!(colorModel instanceof DirectColorModel))
            throw new IllegalArgumentException("colorModel should be an instance of DirectColorModel");

        // Check transfer type
        if(sampleModel.getDataType() != DataBuffer.TYPE_INT)
            throw new IllegalArgumentException("colorModel's transferType should be DataBuffer.TYPE_INT");

        // Check red, green, blue and alpha mask
        DirectColorModel dcm = (DirectColorModel)colorModel;
        if(dcm.getRedMask() != 0x00ff0000)
            throw new IllegalArgumentException("red mask in source should be 0x00ff0000");
        if(dcm.getGreenMask() != 0x0000ff00)
            throw new IllegalArgumentException("green mask in source should be 0x0000ff00");
        if(dcm.getBlueMask() != 0x000000ff)
            throw new IllegalArgumentException("blue mask in source should be 0x000000ff");
        if(dcm.getAlphaMask() != 0xff000000)
            throw new IllegalArgumentException("alpha mask in source should be 0xff000000");
    }

    private boolean isCompatible(ColorModel colorModel,
                                 SampleModel sampleModel){
        ColorSpace cs = colorModel.getColorSpace();
        // Check that model is sRGB or linear RGB
        if((cs != ColorSpace.getInstance(ColorSpace.CS_sRGB))
           &&
           (cs != ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)))
            return false;

        // Check ColorModel is of type DirectColorModel
        if(!(colorModel instanceof DirectColorModel))
            return false;

        // Check transfer type
        if(sampleModel.getDataType() != DataBuffer.TYPE_INT)
            return false;

        // Check red, green, blue and alpha mask
        DirectColorModel dcm = (DirectColorModel)colorModel;
        if(dcm.getRedMask() != 0x00ff0000)
            return false;
        if(dcm.getGreenMask() != 0x0000ff00)
            return false;
        if(dcm.getBlueMask() != 0x000000ff)
            return false;
        if(dcm.getAlphaMask() != 0xff000000)
            return false;
        return true;
    }

    private void checkCompatible(SampleModel model){
        // Check model is ok: should be SinglePixelPackedSampleModel
        if(!(model instanceof SinglePixelPackedSampleModel))
            throw new IllegalArgumentException
                ("MorphologyOp only works with Rasters " +
                 "using SinglePixelPackedSampleModels");
        // Check number of bands
        int nBands = model.getNumBands();
        if(nBands!=4)
            throw new IllegalArgumentException
                ("MorphologyOp only words with Rasters having 4 bands");
        // Check that integer packed.
        if(model.getDataType()!=DataBuffer.TYPE_INT)
            throw new IllegalArgumentException
                ("MorphologyOp only works with Rasters using DataBufferInt");

        // Check bit masks
        int[] bitOffsets=((SinglePixelPackedSampleModel)model).getBitOffsets();
        for(int i=0; i v2)
            return doDilation;
        if (v1 < v2)
            return !doDilation;
        return true;
    }

    /*
     * This method deals with the condition that the Kernel is wider than
     * the Image
     */
    private void specialProcessRow(Raster src, WritableRaster dest){
        final int w = src.getWidth();
        final int h = src.getHeight();

        // Access the integer buffer for each image.
        DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
        DataBufferInt dstDB = (DataBufferInt)dest.getDataBuffer();

        // Offset defines where in the stack the real data begin
        SinglePixelPackedSampleModel sppsm;
        sppsm = (SinglePixelPackedSampleModel)src.getSampleModel();

        final int srcOff = srcDB.getOffset() +
            sppsm.getOffset(src.getMinX() - src.getSampleModelTranslateX(),
                            src.getMinY() - src.getSampleModelTranslateY());


        sppsm = (SinglePixelPackedSampleModel)dest.getSampleModel();
        final int dstOff = dstDB.getOffset() +
            sppsm.getOffset(dest.getMinX() - dest.getSampleModelTranslateX(),
                            dest.getMinY() - dest.getSampleModelTranslateY());

        // Stride is the distance between two consecutive column elements,
        // in the one-dimention dataBuffer
        final int srcScanStride = ((SinglePixelPackedSampleModel)src.getSampleModel()).getScanlineStride();
        final int dstScanStride = ((SinglePixelPackedSampleModel)dest.getSampleModel()).getScanlineStride();

        // Access the pixel value array
        final int[] srcPixels = srcDB.getBankData()[0];
        final int[] destPixels = dstDB.getBankData()[0];

        // The pointer of src and dest indicating where the pixel values are
        int sp, dp;

        // Declaration for the circular buffer's implementation
        // These are the circular buffers' head pointer and
        // the index pointers

        // bufferHead points to the leftmost element in the circular buffer
        int bufferHead;

        int maxIndexA;
        int maxIndexR;
        int maxIndexG;
        int maxIndexB;

        // Temp variables
        int pel, currentPixel, lastPixel;
        int a,r,g,b;
        int a1,r1,g1,b1;

        // If image width is less than or equal to the radiusX,
        // all the pixels share the same max/min value
        if (w<=radiusX){
            for (int i=0; i>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;

                for (int k=1; k>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                    }
                }
                // all the element share the same max/min value
                for (int k=0; k>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;
                bufferA[0] = a;
                bufferR[0] = r;
                bufferG[0] = g;
                bufferB[0] = b;

                for (int k=1; k<=radiusX; k++){
                    currentPixel = srcPixels[sp++];
                    a1 = currentPixel>>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;
                    bufferA[k] = a1;
                    bufferR[k] = r1;
                    bufferG[k] = g1;
                    bufferB[k] = b1;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = k;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = k;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = k;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = k;
                    }
                }
                destPixels[dp++] = (a << 24) | r | g | b;

                //
                // 1 <= j <= w-radiusX-1 : The left margin of each row.
                //
                for (int j=1; j<=w-radiusX-1; j++){
                    lastPixel = srcPixels[sp++];

                    // here is the Alpha channel

                    // we retrieve the previous max/min value
                    a = bufferA[maxIndexA];
                    a1 = lastPixel>>>24;
                    bufferA[j+radiusX] = a1;
                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = j+radiusX;
                    }

                    // now we deal with the Red channel

                    r = bufferR[maxIndexR];
                    r1 = lastPixel&0xff0000;
                    bufferR[j+radiusX] = r1;
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = j+radiusX;
                    }

                    // now we deal with the Green channel

                    g = bufferG[maxIndexG];
                    g1 = lastPixel&0xff00;
                    bufferG[j+radiusX] = g1;
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = j+radiusX;
                    }

                    // now we deal with the Blue channel

                    b = bufferB[maxIndexB];
                    b1 = lastPixel&0xff;
                    bufferB[j+radiusX] = b1;
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = j+radiusX;
                    }
                    // now we have gone through the four channels and
                    // updated the index array. then we'll pack the
                    // new max/min value according to each channel's
                    // max/min vlue

                    destPixels[dp++] = (a << 24) | r | g | b;
                }
                // Now is the inner body of the row:
                // all elements in this segment share the same max/min value
                for (int j = w-radiusX; j<= radiusX; j++){
                    destPixels[dp] = destPixels[dp-1];
                    dp++;
                }
                // Now the circular buffer is full
                // Now is the right margin of the row when radiusX < w <= 2*radiusX
                for (int j = radiusX+1; j>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;

                for (int k=1; k>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                    }
                }
                for (int k=0; k>>24;
                r = pel&0xff0000;
                g = pel&0xff00;
                b = pel&0xff;
                bufferA[0] = a;
                bufferR[0] = r;
                bufferG[0] = g;
                bufferB[0] = b;

                for (int k=1; k<=radiusY; k++){
                    currentPixel = destPixels[cp];
                    cp += dstScanStride;
                    a1 = currentPixel>>>24;
                    r1 = currentPixel&0xff0000;
                    g1 = currentPixel&0xff00;
                    b1 = currentPixel&0xff;
                    bufferA[k] = a1;
                    bufferR[k] = r1;
                    bufferG[k] = g1;
                    bufferB[k] = b1;

                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = k;
                    }
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = k;
                    }
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = k;
                    }
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = k;
                    }
                }
                // fill the first pixel of each column
                destPixels[dp] = (a << 24) | r | g | b;
                dp += dstScanStride;

                //
                // 1 <= i <= h-1-radiusY : The upper margin of each column.
                //
                for (int i=1; i<=h-radiusY-1; i++){
                    lastPixel = destPixels[cp];
                    cp += dstScanStride;

                    // here is the Alpha channel

                    a = bufferA[maxIndexA];
                    a1 = lastPixel>>>24;
                    bufferA[i+radiusY] = a1;
                    if (isBetter(a1, a, doDilation)){
                        a = a1;
                        maxIndexA = i+radiusY;
                    }

                    // now we deal with the Red channel

                    r = bufferR[maxIndexR];
                    r1 = lastPixel&0xff0000;
                    bufferR[i+radiusY] = r1;
                    if (isBetter(r1, r, doDilation)){
                        r = r1;
                        maxIndexR = i+radiusY;
                    }

                    // now we deal with the Green channel

                    g = bufferG[maxIndexG];
                    g1 = lastPixel&0xff00;
                    bufferG[i+radiusY] = g1;
                    if (isBetter(g1, g, doDilation)){
                        g = g1;
                        maxIndexG = i+radiusY;
                    }

                    // now we deal with the Blue channel

                    b = bufferB[maxIndexB];
                    b1 = lastPixel&0xff;
                    bufferB[i+radiusY] = b1;
                    if (isBetter(b1, b, doDilation)){
                        b = b1;
                        maxIndexB = i+radiusY;
                    }
                    // now we have gone through the four channels and
                    // updated the index array. then we'll pack the
                    // new max/min value according to each channel's
                    // max/min vlue

                    destPixels[dp] = (a << 24) | r | g | b;
                    dp += dstScanStride;
                }
                // Now is the inner body of the column
                // when radiusY < h <= 2*radiusY
                for (int i = h-radiusY; i<= radiusY; i++){
                    destPixels[dp] = destPixels[dp-dstScanStride];
                    dp += dstScanStride;
                }
                // The circular buffer is full now

                for (int i = radiusY+1; i
     * The filtering kernel(the operation range for each pixel) is a
     * rectangle of width 2*radiusX+1 and height radiusY+1
     * 

* @param src the Raster to be filtered * @param dest stores the filtered image. If null, a destination will * be created. src and dest can refer to the same Raster, in * which situation the src will be modified. */ public WritableRaster filter(Raster src, WritableRaster dest){ // //This method sorts the pixel values in the kernel window in two steps: // 1. sort by row and store the result into an intermediate matrix // 2. sort the intermediate matrix by column and output the max/min value // into the destination matrix element //check destation if(dest!=null) checkCompatible(dest.getSampleModel()); else { if(src==null) throw new IllegalArgumentException("src should not be null when dest is null"); else dest = createCompatibleDestRaster(src); } final int w = src.getWidth(); final int h = src.getHeight(); // Access the integer buffer for each image. DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer(); DataBufferInt dstDB = (DataBufferInt)dest.getDataBuffer(); // Offset defines where in the stack the real data begin final int srcOff = srcDB.getOffset(); final int dstOff = dstDB.getOffset(); // Stride is the distance between two consecutive column elements, // in the one-dimention dataBuffer final int srcScanStride = ((SinglePixelPackedSampleModel)src.getSampleModel()).getScanlineStride(); final int dstScanStride = ((SinglePixelPackedSampleModel)dest.getSampleModel()).getScanlineStride(); // Access the pixel value array final int[] srcPixels = srcDB.getBankData()[0]; final int[] destPixels = dstDB.getBankData()[0]; // The pointer of src and dest indicating where the pixel values are int sp, dp, cp; // Declaration for the circular buffer's implementation // These are the circular buffers' head pointer and // the index pointers // bufferHead points to the leftmost element in the circular buffer int bufferHead; int maxIndexA; int maxIndexR; int maxIndexG; int maxIndexB; // Temp variables int pel, currentPixel, lastPixel; int a,r,g,b; int a1,r1,g1,b1; // In both round, we are using an optimization approach // to reduce excessive computation to sort values around // the current pixel. The idea is as follows: // ---------------- // |*|V|V|$|N|V|V|&| // ---------------- // For example, suppose we've finished pixel"$" and come // to "N", the radius is 3. Then we must have got the max/min // value and index array for "$". If the max/min is at // "*"(using the index array to judge this), // we need to recompute a max/min and the index array // for "N"; if the max/min is not at "*", we can // reuse the current max/min: we simply compare it with // "&", and update the max/min and the index array. // // The first round: sort by row // if (w<=2*radiusX){ specialProcessRow(src, dest); } // when the size is large enough, we can // use standard optimization method else { final int [] bufferA = new int [rangeX]; final int [] bufferR = new int [rangeX]; final int [] bufferG = new int [rangeX]; final int [] bufferB = new int [rangeX]; for (int i=0; i>>24; r = pel&0xff0000; g = pel&0xff00; b = pel&0xff; bufferA[0] = a; bufferR[0] = r; bufferG[0] = g; bufferB[0] = b; for (int k=1; k<=radiusX; k++){ currentPixel = srcPixels[sp++]; a1 = currentPixel>>>24; r1 = currentPixel&0xff0000; g1 = currentPixel&0xff00; b1 = currentPixel&0xff; bufferA[k] = a1; bufferR[k] = r1; bufferG[k] = g1; bufferB[k] = b1; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = k; } if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = k; } if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = k; } if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = k; } } destPixels[dp++] = (a << 24) | r | g | b; // // 1 <= j <= radiusX : The left margin of each row. // for (int j=1; j<=radiusX; j++){ lastPixel = srcPixels[sp++]; // here is the Alpha channel // we retrieve the previous max/min value a = bufferA[maxIndexA]; a1 = lastPixel>>>24; bufferA[j+radiusX] = a1; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = j+radiusX; } // now we deal with the Red channel r = bufferR[maxIndexR]; r1 = lastPixel&0xff0000; bufferR[j+radiusX] = r1; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = j+radiusX; } // now we deal with the Green channel g = bufferG[maxIndexG]; g1 = lastPixel&0xff00; bufferG[j+radiusX] = g1; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = j+radiusX; } // now we deal with the Blue channel b = bufferB[maxIndexB]; b1 = lastPixel&0xff; bufferB[j+radiusX] = b1; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = j+radiusX; } // now we have gone through the four channels and // updated the index array. then we'll pack the // new max/min value according to each channel's // max/min vlue destPixels[dp++] = (a << 24) | r | g | b; } // // radiusX <= j <= w-1-radiusX : Inner body of the row, between // left and right margins // for (int j=radiusX+1; j<=w-1-radiusX; j++){ lastPixel = srcPixels[sp++]; a1 = lastPixel>>>24; r1 = lastPixel&0xff0000; g1 = lastPixel&0xff00; b1 = lastPixel&0xff; bufferA[bufferHead] = a1; bufferR[bufferHead] = r1; bufferG[bufferHead] = g1; bufferB[bufferHead] = b1; // Alpha channel: // we need to recompute a local max/min // and update the max/min index if (maxIndexA == bufferHead){ a = bufferA[0]; maxIndexA = 0; for (int m= 1; m< rangeX; m++){ a1 = bufferA[m]; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = m; } } } // we can reuse the previous max/min value else { a = bufferA[maxIndexA]; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = bufferHead; } } // Red channel // we need to recompute a local max/min // and update the index array if (maxIndexR == bufferHead){ r = bufferR[0]; maxIndexR = 0; for (int m= 1; m< rangeX; m++){ r1 = bufferR[m]; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = m; } } } // we can reuse the previous max/min value else { r = bufferR[maxIndexR]; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = bufferHead; } } // Green channel // we need to recompute a local max/min // and update the index array if (maxIndexG == bufferHead){ g = bufferG[0]; maxIndexG = 0; for (int m= 1; m< rangeX; m++){ g1 = bufferG[m]; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = m; } } } // we can reuse the previous max/min value else { g = bufferG[maxIndexG]; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = bufferHead; } } // Blue channel // we need to recompute a local max/min // and update the index array if (maxIndexB == bufferHead){ b = bufferB[0]; maxIndexB = 0; for (int m= 1; m< rangeX; m++){ b1 = bufferB[m]; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = m; } } } // we can reuse the previous max/min value else { b = bufferB[maxIndexB]; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = bufferHead; } } destPixels[dp++] = (a << 24) | r | g | b; bufferHead = (bufferHead+1)%rangeX; } // // w-radiusX <= j < w : The right margin of the row // // Head will be updated to indicate the current head // of the remaining buffer int head; // Tail is where the last element is final int tail = (bufferHead == 0)?rangeX-1:bufferHead -1; int count = rangeX-1; for (int j=w-radiusX; j>>24; r = pel&0xff0000; g = pel&0xff00; b = pel&0xff; bufferA[0] = a; bufferR[0] = r; bufferG[0] = g; bufferB[0] = b; for (int k=1; k<=radiusY; k++){ currentPixel = destPixels[cp]; cp += dstScanStride; a1 = currentPixel>>>24; r1 = currentPixel&0xff0000; g1 = currentPixel&0xff00; b1 = currentPixel&0xff; bufferA[k] = a1; bufferR[k] = r1; bufferG[k] = g1; bufferB[k] = b1; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = k; } if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = k; } if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = k; } if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = k; } } destPixels[dp] = (a << 24) | r | g | b; // go to the next element in the column. dp += dstScanStride; // 1 <= i <= radiusY : The upper margin of each row for (int i=1; i<=radiusY; i++){ int maxI = i+radiusY; // we can reuse the previous max/min value lastPixel = destPixels[cp]; cp += dstScanStride; // here is the Alpha channel a = bufferA[maxIndexA]; a1 = lastPixel>>>24; bufferA[maxI] = a1; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = maxI; } // now we deal with the Red channel r = bufferR[maxIndexR]; r1 = lastPixel&0xff0000; bufferR[maxI] = r1; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = maxI; } // now we deal with the Green channel g = bufferG[maxIndexG]; g1 = lastPixel&0xff00; bufferG[maxI] = g1; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = maxI; } // now we deal with the Blue channel b = bufferB[maxIndexB]; b1 = lastPixel&0xff; bufferB[maxI] = b1; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = maxI; } destPixels[dp] = (a << 24) | r | g | b; dp += dstScanStride; } // // radiusY +1 <= i <= h-1-radiusY: // inner body of the column between upper and lower margins // for (int i=radiusY+1; i<=h-1-radiusY; i++){ lastPixel = destPixels[cp]; cp += dstScanStride; a1 = lastPixel>>>24; r1 = lastPixel&0xff0000; g1 = lastPixel&0xff00; b1 = lastPixel&0xff; bufferA[bufferHead] = a1; bufferR[bufferHead] = r1; bufferG[bufferHead] = g1; bufferB[bufferHead] = b1; // here we check if the previous max/min value can be // reused safely and, if possible, reuse the previous // maximum value // Alpha channel: // Recompute the local max/min if (maxIndexA == bufferHead){ a = bufferA[0]; maxIndexA = 0; for (int m= 1; m<= 2*radiusY; m++){ a1 = bufferA[m]; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = m; } } } // we can reuse the previous max/min value else { a = bufferA[maxIndexA]; if (isBetter(a1, a, doDilation)){ a = a1; maxIndexA = bufferHead; } } // Red channel: if (maxIndexR == bufferHead){ r = bufferR[0]; maxIndexR = 0; for (int m= 1; m<= 2*radiusY; m++){ r1 = bufferR[m]; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = m; } } } // we can reuse the previous max/min value else { r = bufferR[maxIndexR]; if (isBetter(r1, r, doDilation)){ r = r1; maxIndexR = bufferHead; } } // Green channel if (maxIndexG == bufferHead){ g = bufferG[0]; maxIndexG = 0; for (int m= 1; m<= 2*radiusY; m++){ g1 = bufferG[m]; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = m; } } } // we can reuse the previous max/min value else { g = bufferG[maxIndexG]; if (isBetter(g1, g, doDilation)){ g = g1; maxIndexG = bufferHead; } } // Blue channel: if (maxIndexB == bufferHead){ b = bufferB[0]; maxIndexB = 0; for (int m= 1; m<= 2*radiusY; m++){ b1 = bufferB[m]; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = m; } } } // we can reuse the previous max/min value else { b = bufferB[maxIndexB]; if (isBetter(b1, b, doDilation)){ b = b1; maxIndexB = bufferHead; } } destPixels[dp] = (a << 24) | r | g | b; dp += dstScanStride; bufferHead = (bufferHead+1)%rangeY; } // // h-radiusY <= i <= h-1 : The lower margin of the column // // head will be updated to indicate the current head // of the remaining buffer: int head; // tail is where the last element in the buffer is final int tail = (bufferHead == 0)?2*radiusY:bufferHead -1; int count = rangeY-1; for (int i= h-radiusY; i





© 2015 - 2024 Weber Informatics LLC | Privacy Policy