🥭 参考博客: Arnold 阿诺德置乱(猫脸变换)图像盲水印注入预处理(Python)
1 回顾:Arnold 公式
A r n o l d \mathsf{Arnold} Arnold 变换公式如下:
[ x n + 1 y n + 1 ] = [ 1 b a a b + 1 ] [ x n y n ] m o d ( N ) \begin{bmatrix} x_{n+1} \\ y_{n+1} \end{bmatrix}= \begin{bmatrix} 1 & b\\ a & ab+1 \end{bmatrix} \begin{bmatrix} x_{n} \\ y_{n} \end{bmatrix} mod(N) [xn+1yn+1]=[1abab+1][xnyn]mod(N)
其中, x n x_n xn 代表置乱 n n n 次后像素的行坐标, y n y_n yn 代表置乱 n n n 次后像素的列坐标。相应地, x n + 1 x_{n+1} xn+1 和 y n + 1 y_{n+1} yn+1 是在 x n x_{n} xn 和 y n y_{n} yn 的基础上再置乱一次的结果。
A r n o l d \mathsf{Arnold} Arnold 逆变换公式如下:
[ x n y n ] = [ a b + 1 − b − a 1 ] [ x n + 1 y n + 1 ] m o d ( N ) \begin{bmatrix} x_{n} \\ y_{n} \end{bmatrix}= \begin{bmatrix} ab+1 & -b\\ -a & 1 \end{bmatrix} \begin{bmatrix} x_{n+1} \\ y_{n+1} \end{bmatrix} mod(N) [xnyn]=[ab+1−a−b1][xn+1yn+1]mod(N)
本质上就是乘置乱矩阵的逆矩阵。
个人理解:所谓的置乱,就是根据公式改变原始图像中每个像素的位置。
2 核心代码实现
A r n o l d \mathsf{Arnold} Arnold 变换的代码实现:
def arnold(img, shuffle_times, a, b):
r, c, d = img.shape
p = np.zeros(img.shape, np.uint8)
for s in range(shuffle_times):
for i in range(r):
for j in range(c):
x = (i + b * j) % r
y = (a * i + (a * b + 1) * j) % c
p[x, y, :] = img[i, j, :]
img = np.copy(p)
return p
A r n o l d \mathsf{Arnold} Arnold 逆变换的代码实现:
def de_arnold(img, shuffle_times, a, b):
r, c, d = img.shape
p = np.zeros(img.shape, np.uint8)
for s in range(shuffle_times):
for i in range(r):
for j in range(c):
x = ((a * b + 1) * i - b * j) % r
y = (- a * i + j) % c
p[x, y, :] = img[i, j, :]
img = np.copy(p)
return p
两个函数只有最里层的 for 循环体不一样。
参数说明:
- i m g \mathsf{img} img 是待处理的图像;
- s h u f f l e _ t i m e s \mathsf{shuffle\_times} shuffle_times 是变换的次数;
- a , b \mathsf{a,b} a,b 是置乱矩阵的参数,可以自行指定;
代码说明:
x = (i + b * j) % r
y = (a * i + (a * b + 1) * j) % c
上述代码没有像公式中那样统一 m o d ( N ) mod(N) mod(N),而是根据行数 r \mathsf{r} r 和列数 c \mathsf{c} c 分别取余。
p[x, y, :] = img[i, j, :]
在变换得到的图像
P
\mathsf{P}
P 的
(
x
,
y
)
\mathsf{(x,y)}
(x,y) 位置上,是原始图像
i
m
g
\mathsf{img}
img 中
(
i
,
j
)
\mathsf{(i,j)}
(i,j) 位置上的像素。此外,:
代表
P
\mathsf{P}
P 复制了
i
m
g
\mathsf{img}
img 的所有通道,从而实现了彩色图像的置乱!
3 完整代码实现
import cv2
import numpy as np
from matplotlib import pyplot as plt
def arnold(img, shuffle_times, a, b):
r, c, d = img.shape
p = np.zeros(img.shape, np.uint8)
for s in range(shuffle_times):
for i in range(r):
for j in range(c):
x = (i + b * j) % r
y = (a * i + (a * b + 1) * j) % c
p[x, y, :] = img[i, j, :]
img = np.copy(p)
return p
def de_arnold(img, shuffle_times, a, b):
r, c, d = img.shape
p = np.zeros(img.shape, np.uint8)
for s in range(shuffle_times):
for i in range(r):
for j in range(c):
x = ((a * b + 1) * i - b * j) % r
y = (- a * i + j) % c
p[x, y, :] = img[i, j, :]
img = np.copy(p)
return p
Img_path = 'white_bear.jpg'
Img = cv2.imread(Img_path)
Img = Img[:, :, [2, 1, 0]]
Img_arnold = arnold(Img, 5, 2, 3)
Img_inverse_arnold = de_arnold(Img_arnold, 5, 2, 3)
plt.subplot(1, 2, 1)
plt.title("arnold", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(Img_arnold)
plt.subplot(1, 2, 2)
plt.title("de_arnold", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(Img_inverse_arnold)
plt.show()
实现效果: