Arnold Transform

AKA cat map.

The classic Arnold Transform is a two-dimensional reversible map. The discrete form of the Arnold Transform is periodic and changes with the size of the image.

Special Arnold Transform

Def.1

$$
\begin{bmatrix}
x’\\
y’
\end{bmatrix}
=
A
\begin{bmatrix}
x\\
y
\end{bmatrix}
\mod N, A =
\begin{bmatrix}
1 & 1 \\
1 & 2
\end{bmatrix}
, 0\le x, y \le 1, 0\le x’, y’ \le 1
$$

$$
\Longrightarrow
\left\{
\begin{array}{lr}
x’ = (x + y) \mod N \\
y’ = (x + 2y) \mod N
\end{array}
\right.
$$
Two-dimensional Arnold Transform.

Def.2

$$
\begin{bmatrix}
x\\
y
\end{bmatrix}
=
A^{-1}
\begin{bmatrix}
x’\\
y’
\end{bmatrix}
\mod N, A^{-1} =
\begin{bmatrix}
2 & -1 \\
-1 & 1
\end{bmatrix}
, 0\le x, y \le 1, 0\le x’, y’ \le 1
$$

$$
\Longrightarrow
\left\{
\begin{array}{lr}
x = (2x’ - y’) \mod N \\
y = (-x’ + y’) \mod N
\end{array}
\right.
$$

Two-dimensional Arnold inverse transformation.

General Arnold Transform

Def.1

$$
\begin{bmatrix}
x’\\
y’
\end{bmatrix}
=
\begin{bmatrix}
1 & a \\
b & ab + 1
\end{bmatrix}
\begin{bmatrix}
x\\
y
\end{bmatrix}
\mod N
$$

$$
\Longrightarrow
\left\{
\begin{array}{lr}
x’ = (x + ay) \mod N \\
y’ = (bx + (ab + 1)y) \mod N
\end{array}
\right.
$$

Def.2

$$
\begin{bmatrix}
x\\
y
\end{bmatrix}
=
\begin{bmatrix}
ab + 1 & -a \\
-b & 1
\end{bmatrix}
\begin{bmatrix}
x’\\
y’
\end{bmatrix}
\mod N
$$

$$
\Longrightarrow
\left\{
\begin{array}{lr}
x = ((ab + 1)x’ - ay’) \mod N \\
y = (-bx’ + y’) \mod N
\end{array}
\right.
$$

Accomplish

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import numpy as np
import cv2

def arnold(image, arnold_times):
a =
b =
# Create a new image, a three-dimensional array of all 0s
decode_image = np.zeros(shape=image.shape)
# Read the length and width pixels of the picture
height, width = image.shape[0], image.shape[1]
N = height # if it is a square, height is equal to width

for time in range(arnold_times): # transformation times
# Traverse the pixel coordinates of the image
for old_x in range(height):
for old_y in range(width):
# Arnold Inverse Transform
new_x = ((a * b + 1) * old_x + (-a) * old_y) % N # N = height
new_y = ((-b) * old_x + old_y) % N # N = width
# Arnold Transform
# new_x = (old_x + a * old_y) % N # N = height
# new_y = (b * old_x + (a * b + 1) * old_y) % N # N = width

decode_image[new_x, new_y, :] = image[old_x, old_y, :]
cv2.imwrite('xxx', decode_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0]) # write as PNG
return decode_image


if __name__ == '__main__':
# imread(path,flag) reads the picture, the default parameter value of loading a color picture is flag=1, the grayscale is 0, the transparency is -1, the result is a three-dimensional array, the first two dimensions are pixel coordinates, and the last one is the channel index
it = cv2.imread('xxx')
arnold(it, 1)
-------------THE END-------------