001: /*
002: * Apollo - Motion capture and animation system
003: * Copyright (c) 2005 Apollo
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or (at your option) any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: *
019: * http://www.gnu.org/copyleft/gpl.html
020: *
021: * @author Giovane.Kuhn - brain@netuno.com.br
022: *
023: */
024: package org.apollo.effect;
025:
026: import java.awt.image.BufferedImage;
027: import java.awt.image.ByteLookupTable;
028: import java.awt.image.DataBuffer;
029: import java.awt.image.DataBufferInt;
030: import java.awt.image.LookupOp;
031: import java.io.IOException;
032: import java.util.ArrayList;
033: import java.util.Collections;
034: import java.util.List;
035:
036: import javax.media.Buffer;
037: import javax.media.Effect;
038: import javax.media.PlugInManager;
039:
040: import org.apollo.ApolloMediaCore;
041:
042: /**
043: * Effect that use a threshold to create a new image. If pixel is lower then
044: * threshold, draw black pixel. Otherwise draw white pixel.
045: *
046: * @author Giovane.Kuhn on 06/04/2005
047: */
048: public final class ThresholdEffect extends ApolloMediaCore implements
049: Effect, IVideoEffect {
050:
051: /** Effect name */
052: private static final String NAME = "Threshold effect";
053:
054: private static final List<String> PROPERTY_NAMES;
055:
056: static {
057: // properties
058: List<String> list = new ArrayList<String>();
059: list.add("red");
060: list.add("green");
061: list.add("blue");
062: list.add("binarize");
063: PROPERTY_NAMES = Collections.unmodifiableList(list);
064:
065: // register
066: PlugInManager.addPlugIn( //
067: ThresholdEffect.class.getName(), //
068: SUPPORTED_FORMATS, //
069: SUPPORTED_FORMATS, //
070: PlugInManager.EFFECT //
071: );
072: try {
073: PlugInManager.commit();
074: } catch (IOException e) {
075: throw new RuntimeException(e);
076: }
077: }
078:
079: /** Threshold operation */
080: private LookupOp thresholdOp;
081:
082: /** Threshold for each channel */
083: private Integer[] threshold = new Integer[] { 0, 0, 0 };
084:
085: /** Binarize image */
086: private Boolean binarize = true;
087:
088: public ThresholdEffect() {
089: // nop
090: }
091:
092: /* instance methods */
093: public Integer getRed() {
094: return threshold[0];
095: }
096:
097: public void setRed(Integer red) {
098: this .threshold[0] = red;
099: this .thresholdOp = createThresholdOp();
100: }
101:
102: public Integer getGreen() {
103: return threshold[1];
104: }
105:
106: public void setGreen(Integer green) {
107: this .threshold[1] = green;
108: this .thresholdOp = createThresholdOp();
109: }
110:
111: public Integer getBlue() {
112: return threshold[2];
113: }
114:
115: public void setBlue(Integer blue) {
116: this .threshold[2] = blue;
117: this .thresholdOp = createThresholdOp();
118: }
119:
120: public Boolean getBinarize() {
121: return binarize;
122: }
123:
124: public void setBinarize(Boolean binarize) {
125: this .binarize = binarize;
126: this .thresholdOp = createThresholdOp();
127: }
128:
129: public List<String> getProperties() {
130: return PROPERTY_NAMES;
131: }
132:
133: public String getName() {
134: return NAME;
135: }
136:
137: public int process(Buffer inputBuffer, Buffer outputBuffer) {
138: long start = System.currentTimeMillis();
139: assert inputFormat.matches(inputBuffer.getFormat());
140: assert outputFormat != null;
141:
142: // input data
143: int[] in = (int[]) inputBuffer.getData();
144: int inLength = inputBuffer.getLength();
145: int inOffset = inputBuffer.getOffset();
146:
147: // update output buffer properties
148: outputBuffer.setFormat(outputFormat);
149: outputBuffer.setLength(inLength);
150: outputBuffer.setOffset(inOffset);
151: if (inLength == 0) {
152: outputBuffer.setData(in);
153: return BUFFER_PROCESSED_OK;
154: }
155:
156: // create buffer image
157: DataBufferInt db = new DataBufferInt(in, inLength, 0);
158: BufferedImage bi = createBufferedImage(db);
159:
160: // threshold operation
161: if (thresholdOp == null) {
162: thresholdOp = createThresholdOp();
163: }
164: bi = thresholdOp.filter(bi, null);
165:
166: // set output buffer data
167: assert bi.getData().getDataBuffer().getDataType() == DataBuffer.TYPE_INT;
168: db = (DataBufferInt) bi.getData().getDataBuffer();
169: outputBuffer.setData(db.getData());
170:
171: System.out.println("[" + this .getClass().getSimpleName()
172: + "] #" + inputBuffer.getSequenceNumber() + " in "
173: + (System.currentTimeMillis() - start) + "ms.");
174: return BUFFER_PROCESSED_OK;
175: }
176:
177: /**
178: * Create new instance to threshold operation
179: *
180: * @return New instance
181: */
182: private LookupOp createThresholdOp() {
183: byte[][] data = new byte[threshold.length][256];
184: for (int i = 0; i < threshold.length; i++) {
185: for (int j = 0; j < 256; j++) {
186: data[i][j] = (byte) (j > threshold[i] ? (binarize ? 255
187: : j) : 0);
188: }
189: }
190: return new LookupOp(new ByteLookupTable(0, data), null);
191: }
192:
193: }
|