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}