1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.filtershow.tools; 18 19 import android.util.Log; 20 21 public class MatrixFit { 22 // Simple implementation of a matrix fit in N dimensions. 23 24 private static final String LOGTAG = "MatrixFit"; 25 26 private double[][] mMatrix; 27 private int mDimension; 28 private boolean mValid = false; 29 private static double sEPS = 1.0f/10000000000.0f; 30 31 public MatrixFit(double[][] from, double[][] to) { 32 mValid = fit(from, to); 33 } 34 35 public int getDimension() { 36 return mDimension; 37 } 38 39 public boolean isValid() { 40 return mValid; 41 } 42 43 public double[][] getMatrix() { 44 return mMatrix; 45 } 46 47 public boolean fit(double[][] from, double[][] to) { 48 if ((from.length != to.length) || (from.length < 1)) { 49 Log.e(LOGTAG, "from and to must be of same size"); 50 return false; 51 } 52 53 mDimension = from[0].length; 54 mMatrix = new double[mDimension +1][mDimension + mDimension +1]; 55 56 if (from.length < mDimension) { 57 Log.e(LOGTAG, "Too few points => under-determined system"); 58 return false; 59 } 60 61 double[][] q = new double[from.length][mDimension]; 62 for (int i = 0; i < from.length; i++) { 63 for (int j = 0; j < mDimension; j++) { 64 q[i][j] = from[i][j]; 65 } 66 } 67 68 double[][] p = new double[to.length][mDimension]; 69 for (int i = 0; i < to.length; i++) { 70 for (int j = 0; j < mDimension; j++) { 71 p[i][j] = to[i][j]; 72 } 73 } 74 75 // Make an empty (dim) x (dim + 1) matrix and fill it 76 double[][] c = new double[mDimension+1][mDimension]; 77 for (int j = 0; j < mDimension; j++) { 78 for (int k = 0; k < mDimension + 1; k++) { 79 for (int i = 0; i < q.length; i++) { 80 double qt = 1; 81 if (k < mDimension) { 82 qt = q[i][k]; 83 } 84 c[k][j] += qt * p[i][j]; 85 } 86 } 87 } 88 89 // Make an empty (dim+1) x (dim+1) matrix and fill it 90 double[][] Q = new double[mDimension+1][mDimension+1]; 91 for (int qi = 0; qi < q.length; qi++) { 92 double[] qt = new double[mDimension + 1]; 93 for (int i = 0; i < mDimension; i++) { 94 qt[i] = q[qi][i]; 95 } 96 qt[mDimension] = 1; 97 for (int i = 0; i < mDimension + 1; i++) { 98 for (int j = 0; j < mDimension + 1; j++) { 99 Q[i][j] += qt[i] * qt[j]; 100 } 101 } 102 } 103 104 // Use a gaussian elimination to solve the linear system 105 for (int i = 0; i < mDimension + 1; i++) { 106 for (int j = 0; j < mDimension + 1; j++) { 107 mMatrix[i][j] = Q[i][j]; 108 } 109 for (int j = 0; j < mDimension; j++) { 110 mMatrix[i][mDimension + 1 + j] = c[i][j]; 111 } 112 } 113 if (!gaussianElimination(mMatrix)) { 114 return false; 115 } 116 return true; 117 } 118 119 public double[] apply(double[] point) { 120 if (mDimension != point.length) { 121 return null; 122 } 123 double[] res = new double[mDimension]; 124 for (int j = 0; j < mDimension; j++) { 125 for (int i = 0; i < mDimension; i++) { 126 res[j] += point[i] * mMatrix[i][j+ mDimension +1]; 127 } 128 res[j] += mMatrix[mDimension][j+ mDimension +1]; 129 } 130 return res; 131 } 132 133 public void printEquation() { 134 for (int j = 0; j < mDimension; j++) { 135 String str = "x" + j + "' = "; 136 for (int i = 0; i < mDimension; i++) { 137 str += "x" + i + " * " + mMatrix[i][j+mDimension+1] + " + "; 138 } 139 str += mMatrix[mDimension][j+mDimension+1]; 140 Log.v(LOGTAG, str); 141 } 142 } 143 144 private void printMatrix(String name, double[][] matrix) { 145 Log.v(LOGTAG, "name: " + name); 146 for (int i = 0; i < matrix.length; i++) { 147 String str = ""; 148 for (int j = 0; j < matrix[0].length; j++) { 149 str += "" + matrix[i][j] + " "; 150 } 151 Log.v(LOGTAG, str); 152 } 153 } 154 155 /* 156 * Transforms the given matrix into a row echelon matrix 157 */ 158 private boolean gaussianElimination(double[][] m) { 159 int h = m.length; 160 int w = m[0].length; 161 162 for (int y = 0; y < h; y++) { 163 int maxrow = y; 164 for (int y2 = y + 1; y2 < h; y2++) { // Find max pivot 165 if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y])) { 166 maxrow = y2; 167 } 168 } 169 // swap 170 for (int i = 0; i < mDimension; i++) { 171 double t = m[y][i]; 172 m[y][i] = m[maxrow][i]; 173 m[maxrow][i] = t; 174 } 175 176 if (Math.abs(m[y][y]) <= sEPS) { // Singular Matrix 177 return false; 178 } 179 for (int y2 = y + 1; y2 < h; y2++) { // Eliminate column y 180 double c = m[y2][y] / m[y][y]; 181 for (int x = y; x < w; x++) { 182 m[y2][x] -= m[y][x] * c; 183 } 184 } 185 } 186 for (int y = h -1; y > -1; y--) { // Back substitution 187 double c = m[y][y]; 188 for (int y2 = 0; y2 < y; y2++) { 189 for (int x = w - 1; x > y - 1; x--) { 190 m[y2][x] -= m[y][x] * m[y2][y] / c; 191 } 192 } 193 m[y][y] /= c; 194 for (int x = h; x < w; x++) { // Normalize row y 195 m[y][x] /= c; 196 } 197 } 198 return true; 199 } 200 } 201