数字水印 | Arnold 变换的 Matlab 代码实现

🍍原文: 图像加密笔记之 Arnold 变换及 Matlab 代码实现

🍍写在前面: 在原文的基础上补全了代码。注意,Matlab 貌似是从 1 开始计数的,而非 0!



1 核心代码

A r n o l d \mathsf{Arnold} Arnold 变换的置乱代码如下:

img_new=zeros(h,w)  % h和w分别是原始图像的高度和宽度
for i=1:n  % n是置乱的轮数
    for y=1:h
        for x=1:w           
            xx=mod((x-1)+b*(y-1),N)+1;  % a和b是可自行指定的参数
            yy=mod(a*(x-1)+(a*b+1)*(y-1),N)+1;        
            img_new(yy,xx)=img(y,x);                
        end
    end
    img=img_new;
end

A r n o l d \mathsf{Arnold} Arnold 变换的还原代码如下:

img=img_new;  % img_new是置乱后的图像
for i=1:n
    for y=1:h
        for x=1:w            
            xx=mod((a*b+1)*(x-1)-b*(y-1),N)+1;
            yy=mod(-a*(x-1)+(y-1),N)+1;
            img_new(yy,xx)=img(y,x);
        end
    end
    img=img_new;
end

简而言之,置乱就是根据公式重新设置每个像素的位置,还原就是根据公式恢复每个像素原本的位置。



2 完整代码

补全后的代码如下,代码说明见后文:

close all
X=imread('white_bear.jpg'); 
I=rgb2gray(X);
[h,w]=size(I);

N=h; % 等于图片长度和宽度
a=2; % 设置参数
b=3; % 设置参数
n=5; % n为置乱轮数

% 置乱--------------------------------------------------
img=I;
img_new=zeros(h,w);
imagesArray=zeros(h,w,3,n);

for i=1:n
    for y=1:h
        for x=1:w           
            xx=mod((x-1)+b*(y-1),N)+1;
            yy=mod(a*(x-1)+(a*b+1)*(y-1),N)+1;        
            img_new(yy,xx)=img(y,x);
        end
    end
    img=cat(3,img_new,img_new,img_new);
    imagesArray(:,:,:,i)=img;
end

figure('Name','置乱前后的图像')
subplot(2,3,1);imshow(I);title('原始图像','FontSize',12);

for i=1:n
    titleStr=['置乱次数=',num2str(i)];
    subplot(2,3,1+i);imshow(uint8(imagesArray(:,:,:,i)));title(titleStr,'FontSize',12);
end

% 还原--------------------------------------------------
img=imagesArray(:,:,:,n);
imagesNewArray=zeros(h, w, 3, n);
imagesNewArray(:,:,:,1)=imagesArray(:,:,:,n);

for i=2:n+1
    for y=1:h
        for x=1:w            
            xx=mod((a*b+1)*(x-1)-b*(y-1),N)+1;
            yy=mod(-a*(x-1)+(y-1),N)+1;        
            img_new(yy,xx)=img(y,x);                   
        end
    end
    img=cat(3,img_new,img_new,img_new);
    imagesNewArray(:,:,:,i)=img;
end

figure('Name','还原前后的图像')
for i=1:n+1
    titleStr=['还原次数=',num2str(i-1)];
    subplot(2,3,i);imshow(uint8(imagesNewArray(:,:,:,i)));title(titleStr,'FontSize',12);
end


2.1 初始设置

close all
X=imread('white_bear.jpg'); 
I=rgb2gray(X);
[h,w]=size(I);

N=h; % 等于图片长度和宽度
a=2; % 设置参数
b=3; % 设置参数
n=5; % n为置乱轮数
  • imread():读取原始图像。请根据自己的需求填写图像名;
  • rgb2gray():将原始图像转换为灰度图像;
  • size():获取原始图像的高度 h \mathsf{h} h 和宽度 w \mathsf{w} w
  • N = h:由于我的原始图像比例为 1 : 1 \mathsf{1:1} 1:1,因此填高度或宽度都行。


2.2 置乱操作

我在核心代码的基础上加入了一个数组和画图的代码。

img=I;
img_new=zeros(h,w);
imagesArray=zeros(h,w,3,n);
  • i m g \mathsf{img} img 变量用于存放原始图像;
  • i m g _ n e w \mathsf{img\_new} img_new 的大小必须与 i m g \mathsf{img} img 的一致,否则无法赋值;
  • i m a g e s A r r a y \mathsf{imagesArray} imagesArray 数组的大小为 n \mathsf{n} n,所存放的变量大小为 h × w × 3 \mathsf{h\times w\times 3} h×w×3

i m a g e s A r r a y \mathsf{imagesArray} imagesArray 数组用于存放置乱 i i i 次后的结果,即第 i i i 轮外层 f o r \mathsf{for} for 循环生成的 i m g _ n e w \mathsf{img\_new} img_new,其中 i m g _ n e w \mathsf{img\_new} img_new 的大小是 h × w \mathsf{h\times w} h×w。后文会解释为什么还需要一个 3 \mathsf{3} 3

for i=1:n
    for y=1:h
        for x=1:w           
            xx=mod((x-1)+b*(y-1),N)+1;
            yy=mod(a*(x-1)+(a*b+1)*(y-1),N)+1;        
            img_new(yy,xx)=img(y,x);
        end
    end
    img=cat(3,img_new,img_new,img_new); % 将灰度图像的通道数变为3
    imagesArray(:,:,:,i)=img;
end

上述代码中,只有倒数第二行、第三行和核心代码的不一样。

  • cat(3,...):在第 3 \mathsf{3} 3 个维度上将 3 \mathsf{3} 3 i m g _ n e w \mathsf{img\_new} img_new 拼接起来;
  • imagesArray(:, :, :, i):将 i m g \mathsf{img} img 存入 i m a g e s A r r a y \mathsf{imagesArray} imagesArray 数组中;

说明:由于画图代码中的 i m s h o w \mathsf{imshow} imshow 函数要求输入值的大小为 M × N × 3 \mathsf{M\times N\times 3} M×N×3,因此我们需要把 i m g _ n e w \mathsf{img\_new} img_new 这一灰度图像的通道数变为 3 \mathsf{3} 3,即把 3 \mathsf{3} 3 i m g _ n e w \mathsf{img\_new} img_new 拼接起来。其中, i m g _ n e w \mathsf{img\_new} img_new 的大小是 M × N × 1   ( M = h , N = w ) \mathsf{M\times N\times 1\ (M=h,N=w)} M×N×1 (M=h,N=w)

figure('Name','置乱前后的图像')
subplot(2,3,1);imshow(I);title('原始图像','FontSize',12);

for i=1:n
    titleStr=['置乱次数=',num2str(i)];
    subplot(2,3,1+i);imshow(uint8(imagesArray(:,:,:,i)));title(titleStr,'FontSize',12);
end
  • f o r \mathsf{for} for 循环前:绘制原始图像;
  • f o r \mathsf{for} for 循环内:绘制置乱 i i i 次后的图像。


2.3 还原操作

同样地,我在核心代码的基础上加入了一个数组和画图的代码。

img=imagesArray(:,:,:,n);
imagesNewArray=zeros(h, w, 3, n);
imagesNewArray(:,:,:,1)=imagesArray(:,:,:,n);
  • i m g \mathsf{img} img 变量用于存放置乱 n n n 次后的结果;
  • i m a g e s N e w A r r a y \mathsf{imagesNewArray} imagesNewArray 数组用于存放还原 i i i 次后的结果;

i m a g e s N e w A r r a y \mathsf{imagesNewArray} imagesNewArray 数组中的元素与 i m a g e s A r r a y \mathsf{imagesArray} imagesArray 数组中的元素前后对应。后续代码逻辑与置乱操作同理,不再赘述。



  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值