homography-transform
Version:
A robust TypeScript implementation of homography-based transformation between 2D planes, ideal for computer vision and image mapping
104 lines (102 loc) • 3.24 kB
JavaScript
// src/Plane.ts
var Plane = class {
constructor(width, height) {
this.width = width;
this.height = height;
if (width <= 0 || height <= 0) {
throw new Error("Plane dimensions must be positive numbers");
}
}
getWidth() {
return this.width;
}
getHeight() {
return this.height;
}
isPointInBounds(point) {
return point.x >= 0 && point.x <= this.width && point.y >= 0 && point.y <= this.height;
}
toString() {
return `Plane(${this.width}x${this.height})`;
}
};
// src/PlaneTransformer.ts
var PlaneTransformer = class {
constructor(sourcePlane, targetPlane, correspondingPoints) {
this.sourcePlane = sourcePlane;
this.targetPlane = targetPlane;
this.correspondingPoints = correspondingPoints;
this.homographyMatrix = null;
if (correspondingPoints.length < 4) {
throw new Error("At least 4 point pairs are required for homography transformation");
}
this.validatePoints();
this.computeHomography();
}
validatePoints() {
for (const pair of this.correspondingPoints) {
if (!this.sourcePlane.isPointInBounds(pair.source)) {
throw new Error(`Source point ${JSON.stringify(pair.source)} is out of bounds`);
}
if (!this.targetPlane.isPointInBounds(pair.target)) {
throw new Error(`Target point ${JSON.stringify(pair.target)} is out of bounds`);
}
}
}
computeHomography() {
const numPoints = this.correspondingPoints.length;
const A = [];
const b = [];
for (let i = 0; i < numPoints; i++) {
const { source, target } = this.correspondingPoints[i];
const { x, y } = source;
const { x: X, y: Y } = target;
A.push([x, y, 1, 0, 0, 0, -x * X, -y * X]);
b.push(X);
A.push([0, 0, 0, x, y, 1, -x * Y, -y * Y]);
b.push(Y);
}
try {
const h = numeric.solve(A, b);
this.homographyMatrix = [
[h[0], h[1], h[2]],
[h[3], h[4], h[5]],
[h[6], h[7], 1]
];
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error("Failed to compute homography matrix: " + errorMessage);
}
}
transform(point) {
if (!this.homographyMatrix) {
throw new Error("Homography matrix has not been computed");
}
if (!this.sourcePlane.isPointInBounds(point)) {
throw new Error("Source point is out of bounds");
}
const H = this.homographyMatrix;
const { x, y } = point;
const w = H[2][0] * x + H[2][1] * y + 1;
const transformedX = (H[0][0] * x + H[0][1] * y + H[0][2]) / w;
const transformedY = (H[1][0] * x + H[1][1] * y + H[1][2]) / w;
return { x: transformedX, y: transformedY };
}
getTransformationError() {
if (!this.homographyMatrix) {
throw new Error("Homography matrix has not been computed");
}
let totalError = 0;
for (const pair of this.correspondingPoints) {
const transformed = this.transform(pair.source);
const dx = transformed.x - pair.target.x;
const dy = transformed.y - pair.target.y;
totalError += Math.sqrt(dx * dx + dy * dy);
}
return totalError / this.correspondingPoints.length;
}
};
export {
Plane,
PlaneTransformer
};