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.demos.sandbox.geom;
031
032import java.awt.event.MouseEvent;
033import java.awt.event.MouseListener;
034import java.awt.event.MouseMotionListener;
035
036import javax.swing.JFrame;
037
038import org.openimaj.image.DisplayUtilities;
039import org.openimaj.image.MBFImage;
040import org.openimaj.image.colour.RGBColour;
041import org.openimaj.math.geometry.shape.Circle;
042import org.openimaj.math.geometry.shape.Ellipse;
043import org.openimaj.math.geometry.shape.EllipseUtilities;
044import org.openimaj.math.matrix.MatrixUtils;
045
046import Jama.Matrix;
047
048public class OnePassSVDEllipse implements MouseListener, MouseMotionListener {
049        private static final double DAMPENING = 0.98;
050        Matrix init = new Matrix(2,10);
051        Matrix point = new Matrix(2,1);
052        double seen = 0;
053        private Matrix mean;
054        private IncrementalSVD svd;
055        private MBFImage image;
056        private JFrame disp;
057        private boolean dragClick;
058        private Ellipse prevEllipse;
059        private boolean initMode = true;
060        public OnePassSVDEllipse() {
061                svd = new IncrementalSVD(2);
062                svd.setDefaultWeighting(1.);
063                image = new MBFImage(400,400,3);
064                disp = DisplayUtilities.displaySimple(image);
065                disp.getContentPane().getComponent(0).addMouseListener(this);
066                disp.getContentPane().getComponent(0).addMouseMotionListener(this);
067        }
068        public static void main(String[] args) {
069                new OnePassSVDEllipse();
070        }
071
072        @Override
073        public void mouseClicked(MouseEvent e) {
074
075                if(initMode){
076                        init.set(0, (int)seen, e.getX());
077                        init.set(1, (int)seen, e.getY());
078                        seen ++;
079                        if (seen == init.getColumnDimension()) {
080                                initMean();
081                                svd.update(MatrixUtils.minusCol(init, mean));
082                                redrawEllipses();
083                        }
084                }
085                else{
086                        point.set(0, 0, e.getX());
087                        point.set(1, 0, e.getY());
088                        updateMean(point);
089                        svd.update(point.minus(mean),DAMPENING);
090                        redrawEllipses();
091                }
092                drawPoint(e.getX(),e.getY());
093                if(initMode  && seen >= init.getColumnDimension()){
094                        initMode = false;
095                }
096        }
097        private void updateMean(Matrix point) {
098                Matrix newMean = mean.times(DAMPENING);
099                newMean.plusEquals(point.times(1 - DAMPENING));
100                mean = newMean;
101        }
102        private void redrawEllipses() {
103                Matrix US = svd.U.times(MatrixUtils.sqrt(svd.Sdiag));
104                Ellipse e = EllipseUtilities.ellipseFromCovariance((float)mean.get(0, 0), (float)mean.get(1, 0), US.times(US.transpose()), 6f);
105                if(prevEllipse!=null)
106                        image.drawShape(prevEllipse, RGBColour.BLUE);
107                image.drawShape(e, RGBColour.RED);
108                image.drawShape(new Circle((float)mean.get(0, 0),(float)mean.get(1, 0),10), RGBColour.GREEN);
109                this.prevEllipse = e;
110                DisplayUtilities.display(image,disp);
111        }
112        private void drawPoint(int x, int y) {
113                image.drawShape(new Circle(x,y,10), RGBColour.RED);
114                DisplayUtilities.display(image,disp);
115        }
116        private void initMean() {
117                mean = MatrixUtils.sumRows(init);
118                mean = mean.times(1.0/init.getColumnDimension());
119        }
120        @Override
121        public void mousePressed(MouseEvent e) {
122                image.fill(RGBColour.BLACK);
123                mouseClicked(e);
124                dragClick = true;
125        }
126        @Override
127        public void mouseReleased(MouseEvent e) {
128                dragClick = false;
129                image.fill(RGBColour.BLACK);
130                redrawEllipses();
131        }
132        @Override
133        public void mouseEntered(MouseEvent e) {
134                // TODO Auto-generated method stub
135
136        }
137        @Override
138        public void mouseExited(MouseEvent e) {
139                // TODO Auto-generated method stub
140
141        }
142        @Override
143        public void mouseDragged(MouseEvent e) {
144                mouseClicked(e);
145        }
146        @Override
147        public void mouseMoved(MouseEvent e) {
148
149        }
150}