UNPKG

@allmaps/transform

Version:

Coordinate transformation functions

120 lines (119 loc) 5.36 kB
import { newArrayMatrix } from '@allmaps/stdlib'; import { BaseTransformation } from './BaseTransformation.js'; import { solveJointlySvd } from '../shared/solve-functions.js'; /** * 2D projective (= perspective) transformation * * For this transformations, the system of equations is solved for x and y jointly. * * See for more information: * Dubrofsky, Elan. "Homography estimation." Diplomová práce. Vancouver: Univerzita Britské Kolumbie 5 (2009). * https://citeseerx.ist.psu.edu/doc/10.1.1.186.4411 * https://www.cs.ubc.ca/sites/default/files/2022-12/Dubrofsky_Elan.pdf */ export class Projective extends BaseTransformation { coefsArrayMatrices; weightsArrays; constructor(sourcePoints, destinationPoints) { super(sourcePoints, destinationPoints, 'projective', 4); // Construct two Nx9 Matrix projectiveCoefsMatrix // −x0 −y0 −1 0 0 0 x'0x0 x'0y0 x'0 // ... // 0 0 0 −x0 −y0 −1 y'0x0 y'0y0 y'0 // ... this.coefsArrayMatrices = [ newArrayMatrix(this.pointCount, 9, 0), newArrayMatrix(this.pointCount, 9, 0) ]; for (let i = 0; i < this.pointCount; i++) { this.coefsArrayMatrices[0][i][0] = -sourcePoints[i][0]; this.coefsArrayMatrices[0][i][1] = -sourcePoints[i][1]; this.coefsArrayMatrices[0][i][2] = -1; this.coefsArrayMatrices[0][i][3] = 0; this.coefsArrayMatrices[0][i][4] = 0; this.coefsArrayMatrices[0][i][5] = 0; this.coefsArrayMatrices[0][i][6] = destinationPoints[i][0] * sourcePoints[i][0]; this.coefsArrayMatrices[0][i][7] = destinationPoints[i][0] * sourcePoints[i][1]; this.coefsArrayMatrices[0][i][8] = destinationPoints[i][0]; this.coefsArrayMatrices[1][i][0] = 0; this.coefsArrayMatrices[1][i][1] = 0; this.coefsArrayMatrices[1][i][2] = 0; this.coefsArrayMatrices[1][i][3] = -sourcePoints[i][0]; this.coefsArrayMatrices[1][i][4] = -sourcePoints[i][1]; this.coefsArrayMatrices[1][i][5] = -1; this.coefsArrayMatrices[1][i][6] = destinationPoints[i][1] * sourcePoints[i][0]; this.coefsArrayMatrices[1][i][7] = destinationPoints[i][1] * sourcePoints[i][1]; this.coefsArrayMatrices[1][i][8] = destinationPoints[i][1]; } } solve() { this.weightsArrays = solveJointlySvd(this.coefsArrayMatrices, this.pointCount); } evaluateFunction(newSourcePoint) { if (!this.weightsArrays) { this.solve(); } if (!this.weightsArrays) { throw new Error('Weights not computed'); } const c = this.weightsArrays[0][2] * newSourcePoint[0] + this.weightsArrays[1][2] * newSourcePoint[1] + this.weightsArrays[2][2]; const num1 = this.weightsArrays[0][0] * newSourcePoint[0] + this.weightsArrays[1][0] * newSourcePoint[1] + this.weightsArrays[2][0]; const num2 = this.weightsArrays[0][1] * newSourcePoint[0] + this.weightsArrays[1][1] * newSourcePoint[1] + this.weightsArrays[2][1]; const newDestinationPoint = [num1 / c, num2 / c]; return newDestinationPoint; } evaluatePartialDerivativeX(newSourcePoint) { if (!this.weightsArrays) { this.solve(); } if (!this.weightsArrays) { throw new Error('Weights not computed'); } const c = this.weightsArrays[0][2] * newSourcePoint[0] + this.weightsArrays[1][2] * newSourcePoint[1] + this.weightsArrays[2][2]; const num1 = this.weightsArrays[0][0] * newSourcePoint[0] + this.weightsArrays[1][0] * newSourcePoint[1] + this.weightsArrays[2][0]; const num2 = this.weightsArrays[0][1] * newSourcePoint[0] + this.weightsArrays[1][1] * newSourcePoint[1] + this.weightsArrays[2][1]; const newDestinationPointPartDerX = [ (c * this.weightsArrays[0][0] - this.weightsArrays[0][2] * num1) / c ** 2, (c * this.weightsArrays[0][1] - this.weightsArrays[0][2] * num2) / c ** 2 ]; return newDestinationPointPartDerX; } evaluatePartialDerivativeY(newSourcePoint) { if (!this.weightsArrays) { this.solve(); } if (!this.weightsArrays) { throw new Error('Weights not computed'); } const c = this.weightsArrays[0][2] * newSourcePoint[0] + this.weightsArrays[1][2] * newSourcePoint[1] + this.weightsArrays[2][2]; const num1 = this.weightsArrays[0][0] * newSourcePoint[0] + this.weightsArrays[1][0] * newSourcePoint[1] + this.weightsArrays[2][0]; const num2 = this.weightsArrays[0][1] * newSourcePoint[0] + this.weightsArrays[1][1] * newSourcePoint[1] + this.weightsArrays[2][1]; const newDestinationPointPartDerY = [ (c * this.weightsArrays[1][0] - this.weightsArrays[1][2] * num1) / c ** 2, (c * this.weightsArrays[1][1] - this.weightsArrays[1][2] * num2) / c ** 2 ]; return newDestinationPointPartDerY; } }