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.math.geometry.transforms.residuals; 031 032import java.util.List; 033 034import org.openimaj.math.geometry.point.Point2d; 035import org.openimaj.math.geometry.transforms.MatrixTransformProvider; 036import org.openimaj.math.model.Model; 037import org.openimaj.math.model.fit.residuals.ResidualCalculator; 038import org.openimaj.util.pair.IndependentPair; 039 040import Jama.Matrix; 041 042/** 043 * The points in the first image are projected by the homography matrix to 044 * produce new estimates of the second image points and the second image point 045 * projected by the inverse homography to produce estimates of the first. 046 * Residuals are computed from both point sets and summed to produce the final 047 * geometric residual value. 048 * 049 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 050 * 051 * @param <M> 052 */ 053public class SymmetricTransferResidual2d<M extends Model<Point2d, Point2d> & MatrixTransformProvider> 054 implements 055 ResidualCalculator<Point2d, Point2d, M> 056{ 057 private Matrix transform; 058 private Matrix transformInv; 059 060 @Override 061 public void setModel(M model) { 062 this.transform = model.getTransform(); 063 064 if (transform.getRowDimension() != 3 || transform.getColumnDimension() != 3) 065 throw new IllegalArgumentException("Transform matrix must be 3x3"); 066 067 transformInv = transform.inverse(); 068 } 069 070 @Override 071 public double computeResidual(IndependentPair<Point2d, Point2d> data) { 072 final Point2d p1 = data.getFirstObject(); 073 final Point2d p2 = data.getSecondObject(); 074 075 final Point2d p1t = p1.transform(transform); 076 final Point2d p2t = p2.transform(transformInv); 077 078 final float p1x = p1.getX(); 079 final float p1y = p1.getY(); 080 final float p1tx = p1t.getX(); 081 final float p1ty = p1t.getY(); 082 final float p2x = p2.getX(); 083 final float p2y = p2.getY(); 084 final float p2tx = p2t.getX(); 085 final float p2ty = p2t.getY(); 086 087 final float dx12t = (p1x - p2tx); 088 final float dy12t = (p1y - p2ty); 089 final float dx1t2 = (p1tx - p2x); 090 final float dy1t2 = (p1ty - p2y); 091 092 return dx12t * dx12t + dy12t * dy12t + dx1t2 * dx1t2 + dy1t2 * dy1t2; 093 } 094 095 @Override 096 public void computeResiduals(List<? extends IndependentPair<Point2d, Point2d>> data, double[] residuals) { 097 for (int i = 0; i < data.size(); i++) { 098 residuals[i] = computeResidual(data.get(i)); 099 } 100 } 101}