001/*
002Copyright 2006 Jerry Huxtable
003
004Licensed under the Apache License, Version 2.0 (the "License");
005you may not use this file except in compliance with the License.
006You may obtain a copy of the License at
007
008   http://www.apache.org/licenses/LICENSE-2.0
009
010Unless required by applicable law or agreed to in writing, software
011distributed under the License is distributed on an "AS IS" BASIS,
012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013See the License for the specific language governing permissions and
014limitations under the License.
015*/
016
017package com.jhlabs.image;
018
019import java.awt.*;
020import java.awt.image.*;
021
022/**
023 * A filter which performs a 3x3 median operation. Useful for removing dust and noise.
024 */
025public class MedianFilter extends WholeImageFilter {
026
027        public MedianFilter() {
028        }
029
030        private int median(int[] array) {
031                int max, maxIndex;
032                
033                for (int i = 0; i < 4; i++) {
034                        max = 0;
035                        maxIndex = 0;
036                        for (int j = 0; j < 9; j++) {
037                                if (array[j] > max) {
038                                        max = array[j];
039                                        maxIndex = j;
040                                }
041                        }
042                        array[maxIndex] = 0;
043                }
044                max = 0;
045                for (int i = 0; i < 9; i++) {
046                        if (array[i] > max)
047                                max = array[i];
048                }
049                return max;
050        }
051
052        private int rgbMedian(int[] r, int[] g, int[] b) {
053                int sum, index = 0, min = Integer.MAX_VALUE;
054                
055                for (int i = 0; i < 9; i++) {
056                        sum = 0;
057                        for (int j = 0; j < 9; j++) {
058                                sum += Math.abs(r[i]-r[j]);
059                                sum += Math.abs(g[i]-g[j]);
060                                sum += Math.abs(b[i]-b[j]);
061                        }
062                        if (sum < min) {
063                                min = sum;
064                                index = i;
065                        }
066                }
067                return index;
068        }
069
070        protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
071                int index = 0;
072                int[] argb = new int[9];
073                int[] r = new int[9];
074                int[] g = new int[9];
075                int[] b = new int[9];
076                int[] outPixels = new int[width * height];
077
078                for (int y = 0; y < height; y++) {
079                        for (int x = 0; x < width; x++) {
080                                int k = 0;
081                                for (int dy = -1; dy <= 1; dy++) {
082                                        int iy = y+dy;
083                                        if (0 <= iy && iy < height) {
084                                                int ioffset = iy*width;
085                                                for (int dx = -1; dx <= 1; dx++) {
086                                                        int ix = x+dx;
087                                                        if (0 <= ix && ix < width) {
088                                                                int rgb = inPixels[ioffset+ix];
089                                                                argb[k] = rgb;
090                                                                r[k] = (rgb >> 16) & 0xff;
091                                                                g[k] = (rgb >> 8) & 0xff;
092                                                                b[k] = rgb & 0xff;
093                                                                k++;
094                                                        }
095                                                }
096                                        }
097                                }
098                                while (k < 9) {
099                                        argb[k] = 0xff000000;
100                                        r[k] = g[k] = b[k] = 0;
101                                        k++;
102                                }
103                                outPixels[index++] = argb[rgbMedian(r, g, b)];
104                        }
105                }
106                return outPixels;
107        }
108
109        public String toString() {
110                return "Blur/Median";
111        }
112
113}
114