001 /* 002 * ReduceToBilevelThreshold 003 * 004 * Copyright (c) 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.color.reduction; 009 010 import net.sourceforge.jiu.data.BilevelImage; 011 import net.sourceforge.jiu.data.GrayIntegerImage; 012 import net.sourceforge.jiu.data.MemoryBilevelImage; 013 import net.sourceforge.jiu.data.PixelImage; 014 import net.sourceforge.jiu.ops.ImageToImageOperation; 015 import net.sourceforge.jiu.ops.MissingParameterException; 016 import net.sourceforge.jiu.ops.WrongParameterException; 017 018 /** 019 * Reduces a {@link net.sourceforge.jiu.data.GrayIntegerImage} to a 020 * {@link net.sourceforge.jiu.data.BilevelImage} by setting all values below 021 * a certain threshold value to black and everything else to white. 022 * <h3>Default value</h3> 023 * If no threshold is specified via {@link #setThreshold(int)}, this operation 024 * uses a default value of ({@link net.sourceforge.jiu.data.IntegerImage#getMaxSample(int)} + 1) / 2. 025 * <h3>Usage example</h3> 026 * This example sets all values below 33 percent luminance to black, 027 * everything else to white. 028 * <pre> 029 * GrayIntegerImage image = ...; 030 * ReduceToBilevelThreshold red = new ReduceToBilevelThreshold(); 031 * red.setInputImage(image); 032 * red.setThreshold(image.getMaxSample(0) / 3); 033 * red.process(); 034 * BilevelImage reducedImage= (BilevelImage)red.getOutputImage(); 035 * </pre> 036 * @author Marco Schmidt 037 */ 038 public class ReduceToBilevelThreshold extends ImageToImageOperation 039 { 040 private Integer threshold; 041 042 /** 043 * Returns the current threshold value, or <code>null</code> if 044 * none was specified and the operation's process method was not 045 * run yet. 046 * @return threshold value 047 */ 048 public Integer getThreshold() 049 { 050 return threshold; 051 } 052 053 private void process(GrayIntegerImage in, BilevelImage out) throws WrongParameterException 054 { 055 final int MAX_SAMPLE = in.getMaxSample(0); 056 if (threshold == null) 057 { 058 threshold = new Integer((MAX_SAMPLE + 1) / 2); 059 } 060 final int THRESHOLD = threshold.intValue(); 061 if (THRESHOLD > MAX_SAMPLE) 062 { 063 throw new WrongParameterException("Threshold must be smaller than or equal to the maximum sample of the input image."); 064 } 065 final int WIDTH = in.getWidth(); 066 final int HEIGHT = in.getHeight(); 067 out.clear(BilevelImage.BLACK); 068 for (int y = 0; y < HEIGHT; y++) 069 { 070 for (int x = 0; x < WIDTH; x++) 071 { 072 if (in.getSample(0, x, y) >= THRESHOLD) 073 { 074 out.putWhite(x, y); 075 } 076 } 077 setProgress(y, HEIGHT); 078 } 079 } 080 081 public void process() throws 082 MissingParameterException, 083 WrongParameterException 084 { 085 PixelImage in = getInputImage(); 086 if (in == null) 087 { 088 throw new MissingParameterException("Input image missing."); 089 } 090 if (!(in instanceof GrayIntegerImage)) 091 { 092 throw new WrongParameterException("Input image must implement GrayIntegerImage."); 093 } 094 PixelImage out = getOutputImage(); 095 if (out == null) 096 { 097 out = new MemoryBilevelImage(in.getWidth(), in.getHeight()); 098 setOutputImage(out); 099 } 100 if (out != null && !(out instanceof BilevelImage)) 101 { 102 throw new WrongParameterException("Output image must implement BilevelImage."); 103 } 104 if (out != null && (in.getWidth() != out.getWidth() || in.getHeight() != out.getHeight())) 105 { 106 throw new WrongParameterException("Input and output images must have the same resolution."); 107 } 108 process((GrayIntegerImage)in, (BilevelImage)out); 109 } 110 111 /** 112 * Sets a new threshold value. 113 * @param newThreshold the new threshold value to be used for this operation 114 * @throws IllegalArgumentException if the threshold value is negative 115 */ 116 public void setThreshold(int newThreshold) 117 { 118 if (newThreshold < 0) 119 { 120 throw new IllegalArgumentException("New threshold value must be 0 or larger."); 121 } 122 threshold = new Integer(newThreshold); 123 } 124 }