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}