001 /* 002 * OilFilter 003 * 004 * Copyright (c) 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.filters; 009 010 import net.sourceforge.jiu.data.IntegerImage; 011 import net.sourceforge.jiu.data.PixelImage; 012 import net.sourceforge.jiu.filters.AreaFilterOperation; 013 import net.sourceforge.jiu.ops.MissingParameterException; 014 import net.sourceforge.jiu.ops.WrongParameterException; 015 016 /** 017 * Applies a filter that makes the image look like an oil painting. 018 * This is accomplished by creating a histogram of the neighboring samples 019 * for each input sample and storing the value that occurs most often 020 * in the output image. 021 * If two or more samples occur an equal number of times, the lowest 022 * sample value is picked. 023 * <h3>Supported image types</h3> 024 * Can process both {@link net.sourceforge.jiu.data.GrayIntegerImage} and 025 * {@link net.sourceforge.jiu.data.RGBIntegerImage}. 026 * Note that this operation becomes very slow with 16 bits per sample 027 * because a lot of runs over a 65536 element array are necessary. 028 * <h3>Usage example</h3> 029 * <pre> 030 * PixelImage image = ...; // some GrayIntegerImage or RGBIntegerImage 031 * OilFilter filter = new OilFilter(); 032 * filter.setArea(5, 5); 033 * filter.setInputImage(image); 034 * filter.process(); 035 * PixelImage filteredImage = filter.getOutputImage(); 036 * </pre> 037 * <h3>Credits</h3> 038 * Idea taken from the <a target="_top" 039 * href="http://www.acme.com/java/software/Acme.JPM.Filters.Oil.html#_top_"> 040 * Oil class</a> of Jef Poskanzer's <a target="_top" 041 * href="http://www.acme.com/java/software/">ACME package</a>. 042 * @author Marco Schmidt 043 */ 044 public class OilFilter extends AreaFilterOperation 045 { 046 private int[] hist; 047 private int[] zeroes; 048 049 public final int computeSample(int[] samples, int numSamples) 050 { 051 /* for each sample find the neighbor that occurs most often 052 in the area surrounding that pixel specified by 053 getAreaWidth x getAreaHeight */ 054 055 // clear histogram 056 System.arraycopy(zeroes, 0, hist, 0, hist.length); 057 058 // initialize histogram 059 int index = numSamples; 060 do 061 { 062 hist[samples[--index]]++; 063 } 064 while (index != 0); 065 066 // now find the value that occurs most frequently 067 int maxIndex = 0; 068 int maxValue = hist[0]; 069 index = 1; 070 final int HIST_LENGTH = hist.length; 071 while (index != HIST_LENGTH) 072 { 073 int value = hist[index]; 074 if (value > maxValue) 075 { 076 maxIndex = index; 077 maxValue = value; 078 } 079 index++; 080 } 081 082 // return value that occurs most frequently 083 // if several samples occur most frequently, the smallest is returned 084 return maxIndex; 085 } 086 087 public void process() throws 088 MissingParameterException, 089 WrongParameterException 090 { 091 ensureInputImageIsAvailable(); 092 PixelImage image = getInputImage(); 093 if (image instanceof IntegerImage) 094 { 095 IntegerImage ii = (IntegerImage)image; 096 int max = ii.getMaxSample(0); 097 int index = 1; 098 while (index < ii.getNumChannels()) 099 { 100 int maxSample = ii.getMaxSample(index++); 101 if (maxSample > max) 102 { 103 max = maxSample; 104 } 105 } 106 hist = new int[max + 1]; 107 zeroes = new int[hist.length]; 108 for (int i = 0; i < zeroes.length; i++) 109 { 110 zeroes[i] = 0; 111 } 112 } 113 super.process(); 114 } 115 }