以一次循环为例:
“拉伸过程”
基本算法
现有参数a、b以及迭代次数T
对于每个像素坐标 (x,y) ,计算新坐标 (x′,y′) :
x′=(x+a⋅y)mod N
y′=(b⋅x+(ab+1)⋅y)mod N
他的本质就是一个规定的矩阵去乘像素坐标的矩阵

对于“算出来的新坐标不会重复”的说明:
核心就是行列式 det(A)=1

将A矩阵用逆矩阵抵消的方法移到x’y’那边

反向求解x与y

这同时也说明这种算法可以逆运行,也就是可以反向解
| 性质 | 结论 |
|---|---|
| 单射 | $T(x_1, y_1) = T(x_2, y_2) \Rightarrow (x_1, y_1) = (x_2, y_2)$ |
| 满射 | 每个目标位置 $(x’, y’)$ 都有原像 $(x, y)$ |
| 双射 | 既是单射又是满射,一一对应 |
“截取”
也就是取模操作,这里略
“循环”
重复上述操作进行循环
加密代码:
import numpy as np
def arnold_transform(img, a=1, b=1, times=1):
"""
Arnold 正向变换(置乱)
参数:
img: 输入图像 (N, N) 的 numpy 数组
a, b: Arnold 变换参数
times: 迭代次数
返回:
置乱后的图像
"""
N = img.shape[0] # 假设是正方形图像
result = img.copy()
for _ in range(times):
new_img = np.zeros_like(result)
for x in range(N):
for y in range(N):
# 计算新位置
nx = (x + a * y) % N
ny = (b * x + (a * b + 1) * y) % N
# 像素搬家:从 (x,y) 搬到 (nx, ny)
new_img[nx, ny] = result[x, y]
result = new_img
return result
def arnold_inverse(img, a=1, b=1, times=1):
"""
Arnold 逆向变换(还原)
"""
N = img.shape[0]
result = img.copy()
for _ in range(times):
new_img = np.zeros_like(result)
for x in range(N):
for y in range(N):
# 计算原位置(逆向公式)
nx = ((a * b + 1) * x - a * y) % N
ny = (-b * x + y) % N
# 像素搬家:从 (x,y) 搬回 (nx, ny)
new_img[nx, ny] = result[x, y]
result = new_img
return result
解密代码:
import matplotlib.pyplot as plt
import cv2
import numpy as np
from PIL import Image
img = cv2.imread('flag.png')
def arnold_encode(image, shuffle_times, a, b):
arnold_image = np.zeros(shape=image.shape)
h, w = image.shape[0], image.shape[1]
N = h # 或N=w
for time in range(shuffle_times):
for ori_x in range(h):
for ori_y in range(w):
new_x = (1*ori_x + b*ori_y)% N
new_y = (a*ori_x + (a*b+1)*ori_y) % N
arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]
image = np.copy(arnold_image)
cv2.imwrite('flag_arnold_encode.png', arnold_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
return arnold_image
def arnold_decode(image, shuffle_times, a, b):
decode_image = np.zeros(shape=image.shape)
h, w = image.shape[0], image.shape[1]
N = h # 或N=w
for time in range(shuffle_times):
for ori_x in range(h):
for ori_y in range(w):
new_x = ((a * b + 1) * ori_x + (-b) * ori_y) % N
new_y = ((-a) * ori_x + ori_y) % N
decode_image[new_x, new_y, :] = image[ori_x, ori_y, :]
cv2.imwrite('flag.png', decode_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
return decode_image
# arnold_encode(img, 1, 2, 3)
arnold_decode(img, 1, 29294, 7302244)
