001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.image.processing.effects;
031
032import org.openimaj.image.FImage;
033import org.openimaj.image.analysis.algorithm.SummedAreaTable;
034import org.openimaj.image.processor.SinglebandImageProcessor;
035import org.openimaj.math.geometry.line.Line2d;
036
037/**
038 * Class to produce a Diorama or "Minature Faking" effect. The effect is
039 * achieved by blurring the image with a kernel that increases size with
040 * distance from a tilt-axis. In this implementation we use a
041 * {@link SummedAreaTable} to efficiently compute box-blurs.
042 * 
043 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
044 * 
045 */
046public class DioramaEffect implements SinglebandImageProcessor<Float, FImage> {
047        Line2d axis;
048
049        /**
050         * Construct with the given tilt axis
051         * 
052         * @param axis
053         */
054        public DioramaEffect(Line2d axis) {
055                this.axis = axis;
056        }
057
058        /**
059         * Get the current tilt axis
060         * 
061         * @return the tilt axis
062         */
063        public Line2d getAxis() {
064                return axis;
065        }
066
067        /**
068         * Set the current tilt axis
069         * 
070         * @param axis
071         *            the tilt axis
072         */
073        public void setAxis(Line2d axis) {
074                this.axis = axis;
075        }
076
077        @Override
078        public void processImage(FImage image) {
079                render(image, new SummedAreaTable(image),
080                                (int) axis.getBeginPoint().getX(),
081                                (int) axis.getBeginPoint().getY(),
082                                (int) axis.getEndPoint().getX(),
083                                (int) axis.getEndPoint().getY());
084        }
085
086        private void render(final FImage image, final SummedAreaTable sat, final int x1, final int y1, final int x2,
087                        final int y2)
088        {
089                final int w = image.width;
090                final int h = image.height;
091                final double s = (w + h) * 2.0;
092
093                final int dx = x2 - x1;
094                final int dy = y2 - y1;
095
096                final float[][] pixels = image.pixels;
097
098                for (int y = 0; y < h; ++y)
099                {
100                        final double yt = y - y1;
101                        for (int x = 0; x < w; ++x)
102                        {
103                                final double xt = x - x1;
104
105                                final double r = (dx * xt + dy * yt) / s;
106                                final int ri = r < 0 ? (int) -r : (int) r;
107
108                                final int yMin = Math.max(0, y - ri);
109                                final int yMax = Math.min(h, y + ri);
110                                final int bh = yMax - yMin;
111
112                                if (bh == 0)
113                                        continue;
114
115                                final int xMin = Math.max(0, x - ri);
116                                final int xMax = Math.min(w, x + ri);
117                                final float scale = 1.0f / (xMax - xMin) / bh;
118
119                                pixels[y][x] = sat.calculateArea(xMin, yMin, xMax, yMax) * scale;
120                        }
121                }
122        }
123}