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.*;
021import com.jhlabs.composite.*;
022
023/**
024 * Edge detection by difference of Gaussians.
025 * @author Jerry Huxtable
026 */
027public class DoGFilter extends AbstractBufferedImageOp {
028
029        private float radius1 = 1;
030        private float radius2 = 2;
031    private boolean normalize = true;
032    private boolean invert;
033        
034        public DoGFilter() {
035        }
036        
037        /**
038         * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
039         * @param radius the radius of the blur in pixels.
040     * @min-value 0
041     * @max-value 100+
042     * @see #getRadius
043         */
044        public void setRadius1(float radius1) {
045                this.radius1 = radius1;
046        }
047        
048        /**
049         * Get the radius of the kernel.
050         * @return the radius
051     * @see #setRadius
052         */
053        public float getRadius1() {
054                return radius1;
055        }
056
057        /**
058         * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
059         * @param radius the radius of the blur in pixels.
060     * @min-value 0
061     * @max-value 100+
062     * @see #getRadius
063         */
064        public void setRadius2(float radius2) {
065                this.radius2 = radius2;
066        }
067        
068        /**
069         * Get the radius of the kernel.
070         * @return the radius
071     * @see #setRadius
072         */
073        public float getRadius2() {
074                return radius2;
075        }
076        
077    public void setNormalize( boolean normalize ) {
078        this.normalize = normalize;
079    }
080    
081    public boolean getNormalize() {
082        return normalize;
083    }
084    
085    public void setInvert( boolean invert ) {
086        this.invert = invert;
087    }
088    
089    public boolean getInvert() {
090        return invert;
091    }
092    
093    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
094        int width = src.getWidth();
095        int height = src.getHeight();
096        BufferedImage image1 = new BoxBlurFilter( radius1, radius1, 3 ).filter( src, null );
097        BufferedImage image2 = new BoxBlurFilter( radius2, radius2, 3 ).filter( src, null );
098        Graphics2D g2d = image2.createGraphics();
099        g2d.setComposite( new SubtractComposite( 1.0f ) );
100        g2d.drawImage( image1, 0, 0, null );
101        g2d.dispose();
102        if ( normalize && radius1 != radius2 ) {
103            int[] pixels = null;
104            int max = 0;
105            for ( int y = 0; y < height; y++ ) {
106                pixels = getRGB( image2, 0, y, width, 1, pixels );
107                for ( int x = 0; x < width; x++ ) {
108                    int rgb = pixels[x];
109                    int r = (rgb >> 16) & 0xff;
110                    int g = (rgb >> 8) & 0xff;
111                    int b = rgb & 0xff;
112                    if ( r > max )
113                        max = r;
114                    if ( g > max )
115                        max = g;
116                    if ( b > max )
117                        max = b;
118                }
119            }
120
121            for ( int y = 0; y < height; y++ ) {
122                pixels = getRGB( image2, 0, y, width, 1, pixels );
123                for ( int x = 0; x < width; x++ ) {
124                    int rgb = pixels[x];
125                    int r = (rgb >> 16) & 0xff;
126                    int g = (rgb >> 8) & 0xff;
127                    int b = rgb & 0xff;
128                    r = r * 255 / max;
129                    g = g * 255 / max;
130                    b = b * 255 / max;
131                    pixels[x] = (rgb & 0xff000000) | (r << 16) | (g << 8) | b;
132                }
133                setRGB( image2, 0, y, width, 1, pixels );
134            }
135
136        }
137
138        if ( invert )
139            image2 = new InvertFilter().filter( image2, image2 );
140
141        return image2;
142    }
143
144        public String toString() {
145                return "Edges/Difference of Gaussians...";
146        }
147}