@Override
    public ImageSource apply(ImageSource source) {
        int width = source.getWidth();
        int height = source.getHeight();

        int[][] result = new int[height][width];

        if (source.isGrayscale()) {
            for (int i = 0; i < height; i++) {

                int iMin = Math.max(0, i - blockRadius);
                int iMax = Math.min(height, i + blockRadius + 1);
                int h = iMax - iMin;

                int jMin = Math.max(0, -blockRadius);
                int jMax = Math.min(width - 1, blockRadius);

                int[] hist = new int[bins + 1];
                int[] clippedHist = new int[bins + 1];

                for (int k = iMin; k < iMax; k++) {
                    for (int l = jMin; l < jMax; l++) {
                        ++hist[roundPositive(source.getGray(l, k) / 255.0f * bins)];
                    }
                }

                for (int j = 0; j < width; j++) {
                    int v = roundPositive(source.getGray(j, i) / 255.0f * bins);

                    int xMin = Math.max(0, j - blockRadius);
                    int xMax = j + blockRadius + 1;
                    int w = Math.min(width, xMax) - xMin;
                    int n = h * w;

                    int limit = (int) (slope * n / bins + 0.5f);

                    /* remove left behind values from histogram */
                    if (xMin > 0) {
                        int xMin1 = xMin - 1;
                        for (int yi = iMin; yi < iMax; ++yi) {
                            --hist[roundPositive(source.getGray(xMin1, yi) / 255.0f * bins)];
                        }
                    }

                    /* add newly included values to histogram */
                    if (xMax <= width) {
                        int xMax1 = xMax - 1;
                        for (int yi = iMin; yi < iMax; ++yi) {
                            ++hist[roundPositive(source.getGray(xMax1, yi) / 255.0f * bins)];
                        }
                    }

                    System.arraycopy(hist, 0, clippedHist, 0, hist.length);
                    int clippedEntries = 0, clippedEntriesBefore;

                    do {
                        clippedEntriesBefore = clippedEntries;
                        clippedEntries = 0;
                        for (int z = 0; z <= bins; ++z) {
                            int d = clippedHist[z] - limit;
                            if (d > 0) {
                                clippedEntries += d;
                                clippedHist[z] = limit;
                            }
                        }

                        int d = clippedEntries / (bins + 1);
                        int m = clippedEntries % (bins + 1);
                        for (int z = 0; z <= bins; ++z) {
                            clippedHist[z] += d;
                        }

                        if (m != 0) {
                            int s = bins / m;
                            for (int z = 0; z <= bins; z += s) {
                                ++clippedHist[z];
                            }
                        }
                    }
                    while (clippedEntries != clippedEntriesBefore);

                    /* build cdf of clipped histogram */
                    int hMin = bins;
                    for (int z = 0; z < hMin; ++z) {
                        if (clippedHist[z] != 0) hMin = z;
                    }

                    int cdf = 0;
                    for (int z = hMin; z <= v; ++z) {
                        cdf += clippedHist[z];
                    }

                    int cdfMax = cdf;
                    for (int z = v + 1; z <= bins; ++z) {
                        cdfMax += clippedHist[z];
                    }

                    int cdfMin = clippedHist[hMin];

                    result[i][j] = roundPositive((cdf - cdfMin) / (float) (cdfMax - cdfMin) * 255.0f);
                }

                for (int a = 0; a < width; a++) {
                    source.setGray(a, i, result[i][a]);
                }
            }
        } else {
            MatrixSource gray = new MatrixSource(source);

            Grayscale gs = new Grayscale(algorithm);
            // It is not OneBandSource
            gs.apply(gray);

            for (int i = 0; i < height; i++) {

                int iMin = Math.max(0, i - blockRadius);
                int iMax = Math.min(height, i + blockRadius + 1);
                int h = iMax - iMin;

                int jMin = Math.max(0, -blockRadius);
                int jMax = Math.min(width - 1, blockRadius);

                int[] hist = new int[bins + 1];
                int[] clippedHist = new int[bins + 1];

                for (int k = iMin; k < iMax; k++) {
                    for (int l = jMin; l < jMax; l++) {
                        ++hist[roundPositive(gray.getGray(l, k) / 255.0f * bins)];
                    }
                }

                for (int j = 0; j < width; j++) {
                    int v = roundPositive(gray.getGray(j, i) / 255.0f * bins);

                    int xMin = Math.max(0, j - blockRadius);
                    int xMax = j + blockRadius + 1;
                    int w = Math.min(width, xMax) - xMin;
                    int n = h * w;

                    int limit = (int) (slope * n / bins + 0.5f);

                    /* remove left behind values from histogram */
                    if (xMin > 0) {
                        int xMin1 = xMin - 1;
                        for (int yi = iMin; yi < iMax; ++yi) {
                            --hist[roundPositive(gray.getGray(xMin1, yi) / 255.0f * bins)];
                        }
                    }

                    /* add newly included values to histogram */
                    if (xMax <= width) {
                        int xMax1 = xMax - 1;
                        for (int yi = iMin; yi < iMax; ++yi) {
                            ++hist[roundPositive(gray.getGray(xMax1, yi) / 255.0f * bins)];
                        }
                    }

                    System.arraycopy(hist, 0, clippedHist, 0, hist.length);
                    int clippedEntries = 0, clippedEntriesBefore;
                    do {
                        clippedEntriesBefore = clippedEntries;
                        clippedEntries = 0;
                        for (int z = 0; z <= bins; ++z) {
                            int d = clippedHist[z] - limit;
                            if (d > 0) {
                                clippedEntries += d;
                                clippedHist[z] = limit;
                            }
                        }

                        int d = clippedEntries / (bins + 1);
                        int m = clippedEntries % (bins + 1);
                        for (int z = 0; z <= bins; ++z)
                            clippedHist[z] += d;

                        if (m != 0) {
                            int s = bins / m;
                            for (int z = 0; z <= bins; z += s)
                                ++clippedHist[z];
                        }
                    }
                    while (clippedEntries != clippedEntriesBefore);

                    /* build cdf of clipped histogram */
                    int hMin = bins;
                    for (int z = 0; z < hMin; ++z) {
                        if (clippedHist[z] != 0) hMin = z;
                    }

                    int cdf = 0;
                    for (int z = hMin; z <= v; ++z) {
                        cdf += clippedHist[z];
                    }

                    int cdfMax = cdf;
                    for (int z = v + 1; z <= bins; ++z) {
                        cdfMax += clippedHist[z];
                    }

                    int cdfMin = clippedHist[hMin];

                    result[i][j] = roundPositive((cdf - cdfMin) / (float) (cdfMax - cdfMin) * 255.0f);
                }

                for (int a = 0; a < width; a++) {
                    float s = (float) result[i][a] / (float) gray.getGray(a, i);

                    float r = ColorHelper.clamp(roundPositive(s * source.getR(a, i)));
                    float g = ColorHelper.clamp(roundPositive(s * source.getG(a, i)));
                    float b = ColorHelper.clamp(roundPositive(s * source.getB(a, i)));

                    int rgb = ColorHelper.getRGB((int) r, (int) g, (int) b);

                    source.setRGB(a, i, rgb);
                }
            }
        }
        return source;
    }
@ Override public ImageSource apply ( ImageSource source ) { int width = source . getWidth ( ) ; int height = source . getHeight ( ) ; int [ ] [ ] result = new int [ height ] [ width ] ; if ( source . isGrayscale ( ) ) { for ( int i = 0 ; i < height ; i ++ ) { int iMin = Math . max ( 0 , i - blockRadius ) ; int iMax = Math . min ( height , i + blockRadius + 1 ) ; int h = iMax - iMin ; int jMin = Math . max ( 0 , - blockRadius ) ; int jMax = Math . min ( width - 1 , blockRadius ) ; int [ ] hist = new int [ bins + 1 ] ; int [ ] clippedHist = new int [ bins + 1 ] ; for ( int k = iMin ; k < iMax ; k ++ ) { for ( int l = jMin ; l < jMax ; l ++ ) { ++ hist [ roundPositive ( source . getGray ( l , k ) / 255.0f * bins ) ] ; } } for ( int j = 0 ; j < width ; j ++ ) { int v = roundPositive ( source . getGray ( j , i ) / 255.0f * bins ) ; int xMin = Math . max ( 0 , j - blockRadius ) ; int xMax = j + blockRadius + 1 ; int w = Math . min ( width , xMax ) - xMin ; int n = h * w ; int limit = ( int ) ( slope * n / bins + 0.5f ) ; if ( xMin > 0 ) { int xMin1 = xMin - 1 ; for ( int yi = iMin ; yi < iMax ; ++ yi ) { -- hist [ roundPositive ( source . getGray ( xMin1 , yi ) / 255.0f * bins ) ] ; } } if ( xMax <= width ) { int xMax1 = xMax - 1 ; for ( int yi = iMin ; yi < iMax ; ++ yi ) { ++ hist [ roundPositive ( source . getGray ( xMax1 , yi ) / 255.0f * bins ) ] ; } } System . arraycopy ( hist , 0 , clippedHist , 0 , hist . length ) ; int clippedEntries = 0 , clippedEntriesBefore ; do { clippedEntriesBefore = clippedEntries ; clippedEntries = 0 ; for ( int z = 0 ; z <= bins ; ++ z ) { int d = clippedHist [ z ] - limit ; if ( d > 0 ) { clippedEntries += d ; clippedHist [ z ] = limit ; } } int d = clippedEntries / ( bins + 1 ) ; int m = clippedEntries % ( bins + 1 ) ; for ( int z = 0 ; z <= bins ; ++ z ) { clippedHist [ z ] += d ; } if ( m != 0 ) { int s = bins / m ; for ( int z = 0 ; z <= bins ; z += s ) { ++ clippedHist [ z ] ; } } } while ( clippedEntries != clippedEntriesBefore ) ; int hMin = bins ; for ( int z = 0 ; z < hMin ; ++ z ) { if ( clippedHist [ z ] != 0 ) hMin = z ; } int cdf = 0 ; for ( int z = hMin ; z <= v ; ++ z ) { cdf += clippedHist [ z ] ; } int cdfMax = cdf ; for ( int z = v + 1 ; z <= bins ; ++ z ) { cdfMax += clippedHist [ z ] ; } int cdfMin = clippedHist [ hMin ] ; result [ i ] [ j ] = roundPositive ( ( cdf - cdfMin ) / ( float ) ( cdfMax - cdfMin ) * 255.0f ) ; } for ( int a = 0 ; a < width ; a ++ ) { source . setGray ( a , i , result [ i ] [ a ] ) ; } } } else { MatrixSource gray = new MatrixSource ( source ) ; Grayscale gs = new Grayscale ( algorithm ) ; gs . apply ( gray ) ; for ( int i = 0 ; i < height ; i ++ ) { int iMin = Math . max ( 0 , i - blockRadius ) ; int iMax = Math . min ( height , i + blockRadius + 1 ) ; int h = iMax - iMin ; int jMin = Math . max ( 0 , - blockRadius ) ; int jMax = Math . min ( width - 1 , blockRadius ) ; int [ ] hist = new int [ bins + 1 ] ; int [ ] clippedHist = new int [ bins + 1 ] ; for ( int k = iMin ; k < iMax ; k ++ ) { for ( int l = jMin ; l < jMax ; l ++ ) { ++ hist [ roundPositive ( gray . getGray ( l , k ) / 255.0f * bins ) ] ; } } for ( int j = 0 ; j < width ; j ++ ) { int v = roundPositive ( gray . getGray ( j , i ) / 255.0f * bins ) ; int xMin = Math . max ( 0 , j - blockRadius ) ; int xMax = j + blockRadius + 1 ; int w = Math . min ( width , xMax ) - xMin ; int n = h * w ; int limit = ( int ) ( slope * n / bins + 0.5f ) ; if ( xMin > 0 ) { int xMin1 = xMin - 1 ; for ( int yi = iMin ; yi < iMax ; ++ yi ) { -- hist [ roundPositive ( gray . getGray ( xMin1 , yi ) / 255.0f * bins ) ] ; } } if ( xMax <= width ) { int xMax1 = xMax - 1 ; for ( int yi = iMin ; yi < iMax ; ++ yi ) { ++ hist [ roundPositive ( gray . getGray ( xMax1 , yi ) / 255.0f * bins ) ] ; } } System . arraycopy ( hist , 0 , clippedHist , 0 , hist . length ) ; int clippedEntries = 0 , clippedEntriesBefore ; do { clippedEntriesBefore = clippedEntries ; clippedEntries = 0 ; for ( int z = 0 ; z <= bins ; ++ z ) { int d = clippedHist [ z ] - limit ; if ( d > 0 ) { clippedEntries += d ; clippedHist [ z ] = limit ; } } int d = clippedEntries / ( bins + 1 ) ; int m = clippedEntries % ( bins + 1 ) ; for ( int z = 0 ; z <= bins ; ++ z ) clippedHist [ z ] += d ; if ( m != 0 ) { int s = bins / m ; for ( int z = 0 ; z <= bins ; z += s ) ++ clippedHist [ z ] ; } } while ( clippedEntries != clippedEntriesBefore ) ; int hMin = bins ; for ( int z = 0 ; z < hMin ; ++ z ) { if ( clippedHist [ z ] != 0 ) hMin = z ; } int cdf = 0 ; for ( int z = hMin ; z <= v ; ++ z ) { cdf += clippedHist [ z ] ; } int cdfMax = cdf ; for ( int z = v + 1 ; z <= bins ; ++ z ) { cdfMax += clippedHist [ z ] ; } int cdfMin = clippedHist [ hMin ] ; result [ i ] [ j ] = roundPositive ( ( cdf - cdfMin ) / ( float ) ( cdfMax - cdfMin ) * 255.0f ) ; } for ( int a = 0 ; a < width ; a ++ ) { float s = ( float ) result [ i ] [ a ] / ( float ) gray . getGray ( a , i ) ; float r = ColorHelper . clamp ( roundPositive ( s * source . getR ( a , i ) ) ) ; float g = ColorHelper . clamp ( roundPositive ( s * source . getG ( a , i ) ) ) ; float b = ColorHelper . clamp ( roundPositive ( s * source . getB ( a , i ) ) ) ; int rgb = ColorHelper . getRGB ( ( int ) r , ( int ) g , ( int ) b ) ; source . setRGB ( a , i , rgb ) ; } } } return source ; }
This effect deals with OneBandSource and Binary MatrixSource
@param source
@return image