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.transform;
031
032import java.util.HashMap;
033import java.util.Map;
034
035import org.openimaj.image.FImage;
036import org.openimaj.math.geometry.point.Point2d;
037import org.openimaj.math.geometry.point.Point2dImpl;
038import org.openimaj.math.geometry.shape.Shape;
039
040/**
041 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
042 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
043 *
044 * Perform a set of matrix transforms on a set of images and construct a single image containing all the pixels (or a window of the pixels)
045 * in the projected space. 
046 */
047public class FProjectionProcessor extends ProjectionProcessor<Float, FImage> {
048        
049        /**
050         * Perform projection but only request data for pixels within the windowed range provided. Specify the background colour, i.e. the value of pixels
051         * with no data post projection.
052         * @param windowMinC left X
053         * @param windowMaxC right X
054         * @param windowMinR top Y
055         * @param windowMaxR bottom Y
056         * @param backgroundColour background colour of pixels with no data
057         * @return projected image within the window
058         */
059        @Override
060        public FImage performProjection(int windowMinC , int windowMaxC , int windowMinR , int windowMaxR , Float backgroundColour) {
061                FImage output = null;
062                output = new FImage(windowMaxC-windowMinC,windowMaxR-windowMinR);
063                if(backgroundColour!=null)
064                        output.fill(backgroundColour);
065                Shape[][] shapeRects = this.getCurrentShapes();
066                for(int y = 0; y < output.getHeight(); y++)
067                {
068                        for(int x = 0; x < output.getWidth(); x++){
069                                Point2d realPoint = new Point2dImpl(windowMinC + x,windowMinR + y);
070                                int i = 0;
071                                for (int j = 0; j < shapeRects.length; j++) {
072                                        if(backgroundColour == null || isInside(j,shapeRects,realPoint)){
073                                                double[][] transform = this.transformsInverted.get(i).getArray();
074                                                
075                                                float xt = (float)transform[0][0] * realPoint.getX() + (float)transform[0][1] * realPoint.getY() + (float)transform[0][2];
076                                                float yt = (float)transform[1][0] * realPoint.getX() + (float)transform[1][1] * realPoint.getY() + (float)transform[1][2];
077                                                float zt = (float)transform[2][0] * realPoint.getX() + (float)transform[2][1] * realPoint.getY() + (float)transform[2][2];
078                                                
079                                                xt /= zt;
080                                                yt /= zt;
081                                                FImage im = this.images.get(i);
082                                                if(backgroundColour!=null)
083                                                        output.pixels[y][x] = im.getPixelInterp(xt, yt,backgroundColour);
084                                                else
085                                                        output.pixels[y][x] = im.getPixelInterp(xt, yt);
086                                        }
087                                        i++;
088                                }
089                        }
090                }
091                return output;
092        }
093        
094        /**
095         * Perform blended projection but only request data for pixels within the windowed range provided. Specify the background colour, i.e. the value of pixels
096         * with no data post projection. This blends any existing pixels to newly added pixels
097         * @param windowMinC left X
098         * @param windowMaxC right X
099         * @param windowMinR top Y
100         * @param windowMaxR bottom Y
101         * @param backgroundColour background colour of pixels with no data
102         * @return projected image within the window
103         */
104        @Override
105        public FImage performBlendedProjection(int windowMinC , int windowMaxC , int windowMinR , int windowMaxR , Float backgroundColour) {
106                FImage output = null;
107                output = new FImage(windowMaxC-windowMinC,windowMaxR-windowMinR);
108                Map<Integer,Boolean> setMap = new HashMap<Integer,Boolean>();
109                FImage blendingPallet = output.newInstance(2, 1);
110                for(int y = 0; y < output.getHeight(); y++)
111                {
112                        for(int x = 0; x < output.getWidth(); x++){
113                                Point2d realPoint = new Point2dImpl(windowMinC + x,windowMinR + y);
114                                int i = 0;
115                                for(Shape s : this.projectedShapes){
116                                        if(s.isInside(realPoint)){
117                                                double[][] transform = this.transformsInverted.get(i).getArray();
118                                                
119                                                float xt = (float)transform[0][0] * realPoint.getX() + (float)transform[0][1] * realPoint.getY() + (float)transform[0][2];
120                                                float yt = (float)transform[1][0] * realPoint.getX() + (float)transform[1][1] * realPoint.getY() + (float)transform[1][2];
121                                                float zt = (float)transform[2][0] * realPoint.getX() + (float)transform[2][1] * realPoint.getY() + (float)transform[2][2];
122                                                
123                                                xt /= zt;
124                                                yt /= zt;
125                                                Float toSet = null;
126                                                if(backgroundColour!=null)
127                                                        toSet = this.images.get(i).getPixelInterp(xt, yt,backgroundColour);
128                                                else
129                                                        if(setMap.get(y * output.getWidth() + x)!=null)
130                                                                toSet = this.images.get(i).getPixelInterp(xt, yt,output.getPixelInterp(x, y));
131                                                        else
132                                                                toSet = this.images.get(i).getPixelInterp(xt, yt);
133                                                // Blend the pixel with the existing pixel
134                                                if(setMap.get(y * output.getWidth() + x)!=null){
135                                                        blendingPallet.pixels[0][1] = toSet;
136                                                        blendingPallet.pixels[0][0] = output.getPixel(x, y);
137                                                        
138                                                        toSet = blendingPallet.getPixelInterp(0.1, 0.5);
139                                                }
140                                                setMap.put(y * output.getWidth() + x,true);
141                                                output.pixels[y][x] = toSet;
142                                        }
143                                        i++;
144                                }
145                        }
146                }
147                return output;
148        }
149
150}