Skip to content

Commit 1fb669c

Browse files
committed
docs: wip add documentation on the new version of transform function
1 parent 7be01a6 commit 1fb669c

File tree

4 files changed

+364
-8
lines changed

4 files changed

+364
-8
lines changed

docs/Features/Geometry/Transform.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,28 @@ _Applies linear transformations to an image, such as scaling, rotation, skewing,
1010

1111
[🖼️ Image options and parameters of `transform` method](https://image-js.github.io/image-js-typescript/classes/Image.html#transform 'github.io link')
1212

13-
`transform` method uses transformation matrix to rotate, translate, and/or scale the image. User needs to pass on the matrix that will be applied to the image. Matrix must have 2 rows and 3 columns:
13+
`transform` method uses transformation matrix to rotate, translate, and/or scale the image.
14+
User needs to pass on the matrix that will be applied to the image. Matrix must have 2 rows and 3 columns:
1415

1516
$$
1617
\begin{bmatrix}
17-
1 & 2 & 3\\
18-
a & b & c
18+
a & b & c\\
19+
d & e & f \\
20+
g & h & i
1921
\end{bmatrix}
2022
$$
2123

22-
Where the first two columns are responsible for image [rotation](https://en.wikipedia.org/wiki/Rotation 'wikipedia link on rotation') and [shear](https://en.wikipedia.org/wiki/Shear_mapping 'wikipedia link on image shearing'), while last column is responsible for image [translation](<https://en.wikipedia.org/wiki/Translation_(geometry)#:~:text=In%20Euclidean%20geometry%2C%20a%20translation,origin%20of%20the%20coordinate%20system> 'wikipedia link on translation').
23-
24-
:::caution
25-
Matrix cannot be singular. Otherwise it cannot be inverted. Click [here](https://en.wikipedia.org/wiki/Invertible_matrix 'wikipedia link on invertible matrices') to learn more.
26-
:::
24+
Where
25+
26+
- the first `a` and `e` are responsible for image scaling
27+
- `b` and `d` are responsible for [shear](https://en.wikipedia.org/wiki/Shear_mapping 'wikipedia link on image shearing'). Combination of these 4 variables allows [rotating](https://en.wikipedia.org/wiki/Rotations_and_reflections_in_two_dimensions 'wikipedia link on rotation'). `c` and `f` are responsible for image [translation](<https://en.wikipedia.org/wiki/Translation_(geometry)#:~:text=In%20Euclidean%20geometry%2C%20a%20translation,origin%20of%20the%20coordinate%20system> 'wikipedia link on translation').
28+
- `g` and `h` are used for an operation called projection.
29+
:::note
30+
`transform()` function can accept 2x3 as well as 3x3 matrix. If matrix's size is 2x3 that it becomes an affine transformation. This means that transformation happens on the same
31+
:::
32+
:::caution
33+
Matrix cannot be singular. Otherwise it cannot be inverted. Click [here](https://en.wikipedia.org/wiki/Invertible_matrix 'wikipedia link on invertible matrices') to learn more.
34+
:::
2735

2836
<TransformDemo />
2937

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
## Synopsis
2+
3+
Image transformations are fundamental operations in computer graphics and image processing that allow you to manipulate the position, size, shape, and perspective of images. This tutorial covers both affine and projective transformations, providing practical examples and clear explanations of how each parameter affects your image.
4+
5+
![Affine transformations](./images/transformations/affine-transform.gif);
6+
7+
## Understanding Transformation Types
8+
9+
In this tutorial, we distinguish between two primary types of transformations:
10+
11+
### Affine Transformations
12+
13+
- **Preserve**: Collinearity and ratios of distances
14+
- **Properties**: Parallel lines remain parallel, straight lines remain straight
15+
- **Use cases**: Scaling, rotation, translation, shearing
16+
- **Matrix size**: 2×3 (the bottom row [0, 0, 1] is implied)
17+
18+
### Projective Transformations
19+
20+
- **Preserve**: Only collinearity (straight lines remain straight)
21+
- **Properties**: Parallel lines may converge, creates perspective effects
22+
- **Use cases**: Perspective correction, 3D projections, keystone correction
23+
- **Matrix size**: 3×3 (full matrix required)
24+
- **The key difference**: affine transformations might stretch, rotate, or shift a rectangle, but parallel lines remain parallel. Projective transformations can make a rectangle appear tilted or receding into the distance, with parallel lines converging to vanishing points.
25+
26+
## The Transformation Matrix
27+
28+
We use this 3×3 matrix throughout the tutorial:
29+
30+
$$
31+
\begin{bmatrix}
32+
a & b & c\\
33+
d & e & f \\
34+
g & h & i
35+
\end{bmatrix}
36+
$$
37+
38+
Each parameter controls specific aspects of the transformation:
39+
40+
`a`, `e`: Scaling (horizontal and vertical)
41+
`b`, `d`: Shearing and rotation
42+
`c`, `f`: Translation (horizontal and vertical)
43+
`g`, `h`: Perspective distortion
44+
`i`: Normalization factor (usually 1)
45+
46+
## Getting Started
47+
48+
First, let's load an image:
49+
50+
```ts
51+
import { readSync } from 'image-processing-library';
52+
53+
const image = readSync('/path/to/image.png');
54+
```
55+
56+
## Affine Transformations
57+
58+
1. Scaling
59+
Scaling changes the size of your image. Parameters a and e control horizontal and vertical scaling respectively.
60+
61+
Uniform Scaling (Maintaining Aspect Ratio)
62+
63+
```ts
64+
// Scale image by factor of 2 (double the size)
65+
const transformationMatrix = [
66+
[2, 0, 0], // a=2 (horizontal scale), b=0, c=0
67+
[0, 2, 0], // d=0, e=2 (vertical scale), f=0
68+
];
69+
70+
const scaledImage = image.transform(transformationMatrix);
71+
```
72+
73+
### Non-uniform Scaling
74+
75+
```ts
76+
// Stretch horizontally by 3x, compress vertically by 0.5x
77+
const transformationMatrix = [
78+
[3, 0, 0], // Horizontal stretch
79+
[0, 0.5, 0], // Vertical compression
80+
];
81+
82+
const stretchedImage = image.transform(transformationMatrix);
83+
```
84+
85+
#### Common Scaling Examples
86+
87+
```ts
88+
// Shrink to half size
89+
const shrinkMatrix = [
90+
[0.5, 0, 0],
91+
[0, 0.5, 0],
92+
];
93+
94+
// Mirror horizontally (flip left-right)
95+
const mirrorMatrix = [
96+
[-1, 0, 0],
97+
[0, 1, 0],
98+
];
99+
100+
// Mirror vertically (flip up-down)
101+
const flipMatrix = [
102+
[1, 0, 0],
103+
[0, -1, 0],
104+
];
105+
```
106+
107+
### Translation
108+
109+
Translation moves your image to a different position. Parameters `c` and `f` control horizontal and vertical movement.
110+
111+
```ts
112+
// Move image 50 pixels right and 30 pixels down
113+
const translationMatrix = [
114+
[1, 0, 50], // c=50 (move right)
115+
[0, 1, 30], // f=30 (move down)
116+
];
117+
118+
const translatedImage = image.transform(translationMatrix);
119+
120+
// Move image 100 pixels left and 50 pixels up
121+
const moveMatrix = [
122+
[1, 0, -100], // Negative values move left
123+
[0, 1, -50], // Negative values move up
124+
];
125+
```
126+
127+
### Rotation
128+
129+
Rotation transforms your image around a point (typically the origin). It uses a combination of parameters a, b, d, and e.
130+
131+
For rotation by angle θ (in radians):
132+
133+
`a` = cos(θ)
134+
`b` = -sin(θ)
135+
`d` = sin(θ)
136+
`e` = cos(θ)
137+
138+
```ts
139+
// Rotate 45 degrees clockwise
140+
const angle = Math.PI / 4; // 45 degrees in radians
141+
const rotationMatrix = [
142+
[Math.cos(angle), -Math.sin(angle), 0],
143+
[Math.sin(angle), Math.cos(angle), 0],
144+
];
145+
146+
const rotatedImage = image.transform(rotationMatrix);
147+
148+
// Rotate 90 degrees counter-clockwise
149+
const rotation90Matrix = [
150+
[0, 1, 0], // cos(90°)=0, -sin(90°)=-(-1)=1
151+
[-1, 0, 0], // sin(90°)=1, cos(90°)=0
152+
];
153+
```
154+
155+
### Rotation Around Image Center
156+
157+
To rotate around the image center instead of the origin, combine translation with rotation:
158+
159+
```ts
160+
function rotateAroundCenter(image, angle) {
161+
const centerX = image.width / 2;
162+
const centerY = image.height / 2;
163+
164+
const cos = Math.cos(angle);
165+
const sin = Math.sin(angle);
166+
167+
// Translate to origin, rotate, translate back
168+
const matrix = [
169+
[cos, -sin, centerX * (1 - cos) + centerY * sin],
170+
[sin, cos, centerY * (1 - cos) - centerX * sin],
171+
];
172+
173+
return image.transform(matrix);
174+
}
175+
176+
const centeredRotation = rotateAroundCenter(image, Math.PI / 6); // 30 degrees
177+
```
178+
179+
### Shearing
180+
181+
Shearing skews the image, making rectangles appear as parallelograms. Parameters b and d control shearing.
182+
183+
```ts
184+
// Horizontal shear - lean the image to the right
185+
const horizontalShearMatrix = [
186+
[1, 0.5, 0], // b=0.5 creates horizontal shear
187+
[0, 1, 0],
188+
];
189+
190+
// Vertical shear - lean the image upward
191+
const verticalShearMatrix = [
192+
[1, 0, 0],
193+
[0.3, 1, 0], // d=0.3 creates vertical shear
194+
];
195+
196+
// Combined shearing
197+
const combinedShearMatrix = [
198+
[1, 0.5, 0], // Horizontal shear
199+
[0.3, 1, 0], // Vertical shear
200+
];
201+
```
202+
203+
### Complex Affine Transformations
204+
205+
You can combine multiple transformations by multiplying matrices or applying them sequentially:
206+
207+
```ts
208+
// Scale, rotate, and translate in one transformation
209+
const angle = Math.PI / 4;
210+
const scale = 1.5;
211+
const translateX = 100;
212+
const translateY = 50;
213+
214+
const complexMatrix = [
215+
[scale * Math.cos(angle), -scale * Math.sin(angle), translateX],
216+
[scale * Math.sin(angle), scale * Math.cos(angle), translateY],
217+
];
218+
219+
const complexTransform = image.transform(complexMatrix);
220+
```
221+
222+
## Projective Transformations
223+
224+
Projective transformations use the full 3×3 matrix, including the bottom row parameters `g`, `h`, and `i`. These create perspective effects and can map rectangular images onto quadrilaterals.
225+
226+
### Understanding Perspective Parameters
227+
228+
`g`, `h`: Control perspective distortion
229+
`i`: Normalization factor (typically 1)
230+
231+
```ts
232+
// Simple perspective transformation
233+
const perspectiveMatrix = [
234+
[1, 0, 0], // Standard scaling and translation
235+
[0, 1, 0],
236+
[0.001, 0, 1], // g=0.001 creates horizontal perspective
237+
];
238+
239+
const perspectiveImage = image.transform(perspectiveMatrix);
240+
```
241+
242+
### Four-Point Mapping
243+
244+
The most common use of projective transformation is mapping an image to fit within four corner points:
245+
246+
```ts
247+
// Define source corners (original image corners)
248+
const sourcePoints = [
249+
[0, 0], // Top-left
250+
[image.width, 0], // Top-right
251+
[image.width, image.height], // Bottom-right
252+
[0, image.height], // Bottom-left
253+
];
254+
255+
// Define destination corners (where you want them to appear)
256+
const destPoints = [
257+
[50, 100], // Top-left moved
258+
[300, 80], // Top-right
259+
[320, 250], // Bottom-right
260+
[30, 280], // Bottom-left
261+
];
262+
263+
// Calculate transformation matrix (implementation depends on library)
264+
const projectionMatrix = calculateProjectionMatrix(sourcePoints, destPoints);
265+
const projectedImage = image.transform(projectionMatrix);
266+
```
267+
268+
### Keystone Correction
269+
270+
Correcting perspective distortion (like photographing a screen at an angle):
271+
272+
```ts
273+
// Correct keystone effect - make trapezoid into rectangle
274+
const keystoneMatrix = [
275+
[1.2, 0.1, -50],
276+
[0.05, 1.1, -20],
277+
[0.0002, 0.0001, 1],
278+
];
279+
280+
const correctedImage = image.transform(keystoneMatrix);
281+
```
282+
283+
## Practical Examples and Use Cases
284+
285+
### Creating Thumbnails with Proper Aspect Ratio
286+
287+
```ts
288+
function createThumbnail(image, maxWidth, maxHeight) {
289+
const scaleX = maxWidth / image.width;
290+
const scaleY = maxHeight / image.height;
291+
const scale = Math.min(scaleX, scaleY); // Maintain aspect ratio
292+
293+
const thumbnailMatrix = [
294+
[scale, 0, 0],
295+
[0, scale, 0],
296+
];
297+
298+
return image.transform(thumbnailMatrix);
299+
}
300+
```
301+
302+
### Photo Straightening
303+
304+
```ts
305+
function straightenPhoto(image, angleDegrees) {
306+
const angle = (angleDegrees \* Math.PI) / 180;
307+
const centerX = image.width / 2;
308+
const centerY = image.height / 2;
309+
310+
const cos = Math.cos(-angle); // Negative for correction
311+
const sin = Math.sin(-angle);
312+
313+
const matrix = [
314+
[cos, -sin, centerX * (1 - cos) + centerY * sin],
315+
[sin, cos, centerY * (1 - cos) - centerX * sin],
316+
];
317+
318+
return image.transform(matrix);
319+
}
320+
```
321+
322+
### Document Scanning Perspective Correction
323+
324+
```ts
325+
function correctDocumentPerspective(image, corners) {
326+
// corners should be [topLeft, topRight, bottomRight, bottomLeft]
327+
const [tl, tr, br, bl] = corners;
328+
329+
// Calculate document dimensions
330+
const width = Math.max(distance(tl, tr), distance(bl, br));
331+
const height = Math.max(distance(tl, bl), distance(tr, br));
332+
333+
// Target rectangle corners
334+
const targetCorners = [
335+
[0, 0],
336+
[width, 0],
337+
[width, height],
338+
[0, height],
339+
];
340+
341+
const matrix = calculateProjectionMatrix(corners, targetCorners);
342+
return image.transform(matrix);
343+
}
344+
345+
function distance(p1, p2) {
346+
return Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2);
347+
}
348+
```
178 KB
Loading
19.3 KB
Loading

0 commit comments

Comments
 (0)