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 java.util.*; 022 023/** 024 * An experimental filter which can be used for keying against a clean shot. Given a source image, a clean image and a destination image, 025 * the filter replaces all pixels in the source which nearly equal the equivalent clean pixel by destination pixels. 026 */ 027public class KeyFilter extends AbstractBufferedImageOp { 028 029 private float hTolerance = 0; 030 private float sTolerance = 0; 031 private float bTolerance = 0; 032 private BufferedImage destination; 033 private BufferedImage cleanImage; 034 035 public KeyFilter() { 036 } 037 038 /** 039 * Set the hue tolerance of the image in the range 0..1. 040 * @param hTolerance the tolerance 041 * @see #getHTolerance 042 */ 043 public void setHTolerance( float hTolerance ) { 044 this.hTolerance = hTolerance; 045 } 046 047 /** 048 * Get the hue tolerance. 049 * @return the tolerance 050 * @see #setHTolerance 051 */ 052 public float getHTolerance() { 053 return hTolerance; 054 } 055 056 /** 057 * Set the saturation tolerance of the image in the range 0..1. 058 * @param sTolerance the tolerance 059 * @see #getSTolerance 060 */ 061 public void setSTolerance( float sTolerance ) { 062 this.sTolerance = sTolerance; 063 } 064 065 /** 066 * Get the saturation tolerance. 067 * @return the tolerance 068 * @see #setSTolerance 069 */ 070 public float getSTolerance() { 071 return sTolerance; 072 } 073 074 /** 075 * Set the brightness tolerance of the image in the range 0..1. 076 * @param bTolerance the tolerance 077 * @see #getBTolerance 078 */ 079 public void setBTolerance( float bTolerance ) { 080 this.bTolerance = bTolerance; 081 } 082 083 /** 084 * Get the brightness tolerance. 085 * @return the tolerance 086 * @see #setBTolerance 087 */ 088 public float getBTolerance() { 089 return bTolerance; 090 } 091 092 /** 093 * Set the destination image. 094 * @param destination the destination image 095 * @see #getDestination 096 */ 097 public void setDestination( BufferedImage destination ) { 098 this.destination = destination; 099 } 100 101 /** 102 * Get the destination image. 103 * @return the destination image 104 * @see #setDestination 105 */ 106 public BufferedImage getDestination() { 107 return destination; 108 } 109 110 /** 111 * Get the clean image. 112 * @param cleanImage the clean image 113 * @see #getCleanImage 114 */ 115 public void setCleanImage( BufferedImage cleanImage ) { 116 this.cleanImage = cleanImage; 117 } 118 119 /** 120 * Get the clean image. 121 * @return the clean image 122 * @see #setCleanImage 123 */ 124 public BufferedImage getCleanImage() { 125 return cleanImage; 126 } 127 128 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 129 int width = src.getWidth(); 130 int height = src.getHeight(); 131 int type = src.getType(); 132 WritableRaster srcRaster = src.getRaster(); 133 134 if ( dst == null ) 135 dst = createCompatibleDestImage( src, null ); 136 WritableRaster dstRaster = dst.getRaster(); 137 138 if ( destination != null && cleanImage != null ) { 139 float[] hsb1 = null; 140 float[] hsb2 = null; 141 int[] inPixels = null; 142 int[] outPixels = null; 143 int[] cleanPixels = null; 144 for ( int y = 0; y < height; y++ ) { 145 inPixels = getRGB( src, 0, y, width, 1, inPixels ); 146 outPixels = getRGB( destination, 0, y, width, 1, outPixels ); 147 cleanPixels = getRGB( cleanImage, 0, y, width, 1, cleanPixels ); 148 for ( int x = 0; x < width; x++ ) { 149 int rgb1 = inPixels[x]; 150 int out = outPixels[x]; 151 int rgb2 = cleanPixels[x]; 152 153 int r1 = (rgb1 >> 16) & 0xff; 154 int g1 = (rgb1 >> 8) & 0xff; 155 int b1 = rgb1 & 0xff; 156 int r2 = (rgb2 >> 16) & 0xff; 157 int g2 = (rgb2 >> 8) & 0xff; 158 int b2 = rgb2 & 0xff; 159 hsb1 = Color.RGBtoHSB( r1, b1, g1, hsb1 ); 160 hsb2 = Color.RGBtoHSB( r2, b2, g2, hsb2 ); 161// int tolerance = (int)(255*tolerance); 162// return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance; 163 164 // if ( PixelUtils.nearColors( in, clean, (int)(255*tolerance) ) ) 165 if ( Math.abs( hsb1[0] - hsb2[0] ) < hTolerance && Math.abs( hsb1[1] - hsb2[1] ) < sTolerance && Math.abs( hsb1[2] - hsb2[2] ) < bTolerance ) 166 inPixels[x] = out; 167 else 168 inPixels[x] = rgb1; 169 } 170 setRGB( dst, 0, y, width, 1, inPixels ); 171 } 172 } 173 174 return dst; 175 } 176 177 public String toString() { 178 return "Keying/Key..."; 179 } 180}