homography-transform
Version:
A robust TypeScript implementation of homography-based transformation between 2D planes, ideal for computer vision and image mapping
85 lines (69 loc) • 2.9 kB
text/typescript
import { Plane, Point } from './Plane';
import { PlaneTransformer, PointPair } from './PlaneTransformer';
import numeric from 'numeric';
// Mock numeric if it's not available in the test environment
(global as any).numeric = numeric;
describe('PlaneTransformer', () => {
// Test case with mobile screen and camera image
const mobileScreen = new Plane(1080, 1920);
const cameraImage = new Plane(640, 480);
// Define test point pairs (these are example points that would map between the two planes)
const pointPairs: PointPair[] = [
{ source: { x: 0, y: 0 }, target: { x: 0, y: 0 } },
{ source: { x: 1080, y: 0 }, target: { x: 640, y: 0 } },
{ source: { x: 0, y: 1920 }, target: { x: 0, y: 480 } },
{ source: { x: 1080, y: 1920 }, target: { x: 640, y: 480 } }
];
let transformer: PlaneTransformer;
beforeEach(() => {
transformer = new PlaneTransformer(mobileScreen, cameraImage, pointPairs);
});
test('transforms corner points correctly', () => {
const errorThreshold = 1e-10;
// Test all corner points
pointPairs.forEach(pair => {
const transformed = transformer.transform(pair.source);
const dx = transformed.x - pair.target.x;
const dy = transformed.y - pair.target.y;
const error = Math.sqrt(dx * dx + dy * dy);
expect(error).toBeLessThan(errorThreshold);
});
});
test('transforms middle point', () => {
// Test a point in the middle of the plane
const middleSource: Point = {
x: mobileScreen.getWidth() / 2,
y: mobileScreen.getHeight() / 2
};
const expectedTarget: Point = {
x: cameraImage.getWidth() / 2,
y: cameraImage.getHeight() / 2
};
const transformed = transformer.transform(middleSource);
const dx = transformed.x - expectedTarget.x;
const dy = transformed.y - expectedTarget.y;
const error = Math.sqrt(dx * dx + dy * dy);
expect(error).toBeLessThan(1.0); // Allow for some numerical error
});
test('rejects out of bounds points', () => {
const outOfBoundsPoint: Point = {
x: mobileScreen.getWidth() + 100,
y: mobileScreen.getHeight() + 100
};
expect(() => {
transformer.transform(outOfBoundsPoint);
}).toThrow('Source point is out of bounds');
});
test('requires at least 4 point pairs', () => {
const insufficientPoints = pointPairs.slice(0, 3);
expect(() => {
new PlaneTransformer(mobileScreen, cameraImage, insufficientPoints);
}).toThrow('At least 4 point pairs are required');
});
test('computes reasonable transformation error', () => {
const error = transformer.getTransformationError();
expect(error).toBeDefined();
expect(error).toBeGreaterThanOrEqual(0);
expect(error).toBeLessThan(1.0); // Expect small error for perfect corner mappings
});
});