基于奇异值分解的图像压缩和信息隐藏

基于奇异值分解的图像压缩和信息隐藏

将图像进行奇异值分解后,通过对对角矩阵进行一系列操作,可以达到压缩图像以及信息隐藏的目的。不仅如此,随着计算机网络和网络技术的不断发展,数字图像、音频和视频产品越来越需要一种有效的版权保护方案。利用奇异值分解实现数字图像水印技术,将水印图片置乱再隐写入图像的方法可以在一定程度上避免被破译;为了进一步防止破译,结合离散余弦变化以及奇异值分解的数字水印技术更加安全。

基于奇异值分解的图像压缩

灰度图

一张灰度图是由m*n的矩阵构成的,矩阵的每一个元素是处于0~255的整数,每一个元素就代表着对应像素点的灰度。而一张彩色图像可以转化为灰度图rgb2gray(),即一个非负矩阵A

奇异值分解

奇异值分解svd()可以理解为利用正交向量的性质,将矩阵A包含的**“信息空间”分解为r个相互正交的“子信息空间”,每一个“子信息空间”中都包含了一定的原图像信息。相应的,删除k个“子信息空间”可以达到降维的目的,k取合适的值时,人类肉眼无法清楚分辨是否有信息损失,就可以达到兼顾保留图像信息压缩图像文件大小**的目的。

矩阵A的奇异值分解定义如下:
A = U S V T A=USV^T A=USVT
具体步骤是:

  • 奇异值分解矩阵A,得到正交矩阵U、V和对角矩阵S
  • 取出矩阵U、V的前k行数据,构成 U 1 , V 1 U_1, V_1 U1,V1,S化为** k × k k \times k k×k的对角矩阵** S 1 S_1 S1

A 1 = U 1 S 1 V 1 T A_1=U_1S_1V_1^T A1=U1S1V1T

clear;
% 使用SVD压缩图像
%% k=1000
k = 1000;
img = double(rgb2gray(imread("Always like this.png")));
[U, S, V] = svd(img);
U_1 = U(:, 1:k);
SS = diag(S);
SSS = SS(1:k);
S_1 = diag(SSS);
V_1 = V(:, 1:k);
img_1000 = U_1*S_1*V_1';
figure(1);
subplot(1, 3, 1);
imshow(mat2gray(img_1000));
title('k=1000');
%% k=100
k = 100;
U_2 = U(:, 1:k);
SSS = SS(1:k);
S_2 = diag(SSS);
V_2 = V(:, 1:k);
img_100 = U_2*S_2*V_2';
subplot(1, 3, 2);
imshow(mat2gray(img_100));
title('k=100');
%% k=50
k = 50;
U_3 = U(:, 1:k);
SSS = SS(1:k);
S_3 = diag(SSS);
V_3 = V(:, 1:k);
img_50 = U_3*S_3*V_3';
subplot(1, 3, 3);
imshow(mat2gray(img_50));
title('k=50');

代码运行结果:

基于奇异值分解的图像压缩和信息隐藏_第1张图片

基于奇异值分解的数字图像水印

将SVD应用于数字图像水印技术的主要理论背景是:

  1. 图像的奇异值稳定性非常好,即当图像被施加小的扰动时,图像的奇异值不会有太大的变化;
  2. 奇异值所表现的是图像的内蕴特性而非视觉特性。

具体步骤:

  • 将图像A奇异值分解,得到$ U、S、V $
  • 将水印$ W\in R_{n\times n} 叠 加 到 对 角 矩 阵 叠加到对角矩阵 S $ 上,$ S+ \alpha W $
  • 对$ S+ \alpha W 进 行 奇 异 值 分 解 , 得 到 进行奇异值分解,得到 U, S_1, V_1^T $
  • 将$ U, S_1, V^T $相乘,就可以得到包含水印的图像

A = > U S V T A => USV^T A=>USVT

S + α W = > U 1 S 1 V 1 T S+\alpha W => U_1S_1V_1^T S+αW=>U1S1V1T

A ^ = U S 1 V T \hat{A}=US_1V^T A^=US1VT

如果想要提取水印,则只需要进行简单的求逆,再次不多赘述。

生成水印图

此处的水印图我使用的是二维码,采用Python中qrcode库生成。

import qrcode
qr = qrcode.QRCode(
    version = 2,
    box_size = 8,
    border = 0
)
qr.make('Life is fantastic')
img = qr.make_image();
with open('watermark.png', 'wb') as f:
    img.save(f)

Arnold置乱

Arnold置乱(也称作cat置乱)可以对图像进行置乱,使得原本有意义的图像变成一张无意义的图像。其矩阵变换公式是:
( x 1 y 1 ) = [ 1 1 1 2 ] ( x y ) m o d ( N ) \begin{pmatrix}x_1\\y_1\\\end{pmatrix}=\begin{bmatrix} 1&1\\1&2\\\end{bmatrix}\begin{pmatrix}x\\y\\\end{pmatrix}mod(N) (x1y1)=[1112](xy)mod(N)
其中mod是取模运算,N是正方形图像的边长, ( x 1 , y 1 ) (x_1, y_1) (x1,y1) ( x , y ) (x, y) (x,y)变换之后的坐标位置。

对于图像而言,这里的位置移动,实际上是对应点的灰度值或者RGB值的移动,即将原来 ( x , y ) (x, y) (x,y)的灰度值或者RGB颜色分量移动到 ( x 1 , y 1 ) (x_1, y_1) (x1,y1)如果对一个数字图像迭代地使用离散化的Arnold变换,即将左端输出的 ( x 1 , y 1 ) (x_1, y_1) (x1,y1)作为下一次Arnold变换的输入,则可以重复这个过程一直做下去。当迭代到某一步时,如果出现的图像呈现出杂乱无章、无法辨识的情况,那么就得到了一幅置乱图。

相应的反变换公式如下:
( x 2 y 2 ) = [ 2 − 1 − 1 1 ] ( x 1 y 1 ) m o d ( N ) \begin{pmatrix}x_2\\y_2\\\end{pmatrix}=\begin{bmatrix} 2&-1\\-1&1\\\end{bmatrix}\begin{pmatrix}x_1\\y_1\\\end{pmatrix}mod(N) (x2y2)=[2111](x1y1)mod(N)

水印插入

为了提高加密程度,我们在插入水印之前先对水印图像进行预处理,即对它进行Arnold置乱,然后再执行基于奇异值分解的数字水印插入。

clear;
%% 图片预处理以及将水印图片加密进目标图片
% 首先将目标图像转化为灰度图
img = imread('Always like this.png');
watermark = double(imread('watermark.jpg'));
img_grayed = double(rgb2gray(img));
imwrite(uint8(img_grayed), 'AlwaysLikeThis_grayed.jpg');
figure(1);
subplot(2, 3, 1);
imshow(uint8(img_grayed));
title("原始图像");
subplot(2, 3, 2);
imshow(watermark);
title("原始水印");
key = 10; % key是对watermark进行Arnold置乱的次数
a = 3;b = 5;
[prow, pcol] = size(img_grayed);
[wrow, wcol] = size(watermark);
% 进行arnold置乱
watermark_arnolded = zeros(wrow, wcol);
for i = 1:key
    for y = 1:wrow
        for x = 1:wcol
            xx = mod((x-1)+b*(y-1), wrow)+1;
            yy = mod(a*(x-1)+(a*b+1)*(y-1), wrow)+1;
            watermark_arnolded(yy, xx) = watermark(y, x);
        end
    end 
    watermark = watermark_arnolded;
end 
subplot(2, 3, 3);
imshow(watermark_arnolded);
title("arnold置乱后的watermark");
% 对原始图像进行奇异值分解
[U, S, V] = svd(img_grayed);
S_copy = S;
alpha = 0.1; % 叠加强度
for i = 1:wrow
    for j = 1:wcol
        S(i, j) = S(i, j) + alpha * watermark_arnolded(i, j);
    end
end
[U_1, S_1, V_1] = svd(S);
img_watered = U*S_1*V';
subplot(2, 3, 4);
imshow(uint8(img_watered));
title("添加水印的图像");
%% 将水印图片提取
[U_2, S_2, V_2] = svd(img_watered);
D = U_1 * S_2 * V_1';
watermark_res = zeros(wrow, wcol);
for i = 1:wrow
    for j = 1:wcol
        watermark_res(i, j) = (1/alpha)*(D(i, j) - S_copy(i, j));
    end 
end
subplot(2, 3, 5);
imshow(watermark_res);
title('提取出的watermark');
% 还原watermark
watermark_recovery = zeros(wrow, wcol);
for i = 1:key
    for y = 1:wrow
        for x = 1:wcol
            xx=mod((a*b+1)*(x-1)-b*(y-1), wrow)+1;
            yy=mod(-a*(x-1)+(y-1), wrow)+1;
            watermark_recovery(yy, xx) = watermark_res(y, x);
        end
    end 
    watermark_res = watermark_recovery;
end
subplot(2, 3, 6);
imshow(watermark_recovery);
title("还原提取出的watermark");

代码运行结果:

基于奇异值分解的图像压缩和信息隐藏_第2张图片

基于离散余弦变换和奇异值分解的数字水印技术

离散余弦变换(DCT)

离散余弦变换 DCT是数据通信中最常用到的 变换编码的方法。图像经过DCT变换后其系数有较 好的感觉容量,利用此特点可以将水印信息嵌入到 DCT系数中,而不会引起图像质量的较大改变。

DCT系数分为直流分量和交流分量。直流分量 代表图像的亮度值,交流分量又分为高频带,中频带 和低频带。高频系数一般很小,人眼对高频部分失真 不太敏感,在图像做Jpeg等压缩处理时会将高频部分 舍弃,若在高频嵌入水印鲁棒性会降低,所以一般选 择将水印嵌入低频中。低频是数据块中能量集中区 域,也就是说经过DCT变换后,图像的大部分重要信 息都集中在DCT的低频系数里,所以在嵌入水印是 要控制好强度否则会造成图像质量下降。

二维离散余弦变换公式:
F ( u , v ) = c ( u ) c ( v ) ∑ x = 0 N − 1 ∑ y = 0 N − 1 f ( x , y ) c o s ( 2 x + 1 2 N u π ) c o s ( 2 y + 1 2 N v π )      x , y , u , v = 0 , 1 , . . . , N − 1 c ( u ) = c ( v ) = { 1 2    u = 0 , v = 0 1    其 他 F(u, v)=c(u)c(v)\sum_{x=0}^{N-1}\sum_{y=0}^{N-1}f(x, y)cos(\frac{2x+1}{2N}u\pi)cos(\frac{2y+1}{2N}v\pi)\ \ \ \ x,y,u,v=0,1,...,N-1 \\ c(u)=c(v)=\begin{cases} \frac{1}{\sqrt{2}}\ \ u=0,v=0\\ 1 \ \ 其他 \end{cases} F(u,v)=c(u)c(v)x=0N1y=0N1f(x,y)cos(2N2x+1uπ)cos(2N2y+1vπ)    x,y,u,v=0,1,...,N1c(u)=c(v)={2 1  u=0,v=01  
二维离散余弦逆变换公式:
f ( x , y ) = 2 N ∑ u = 0 N − 1 ∑ v = 0 N − 1 F ( u , v ) c o s ( 2 x + 1 2 N u π ) c o s ( 2 y + 1 2 N v π )      x , y , u , v = 0 , 1 , . . . , N − 1 c ( u ) = c ( v ) = { 1 2    u = 0 , v = 0 1    其 他 f(x, y)=\frac{2}{N} \sum_{u=0}^{N-1} \sum_{v=0}^{N-1}F(u, v)cos(\frac{2x+1}{2N}u\pi)cos(\frac{2y+1}{2N}v\pi)\ \ \ \ x,y,u,v=0,1,...,N-1 \\ c(u)=c(v)=\begin{cases} \frac{1}{\sqrt{2}}\ \ u=0,v=0\\ 1 \ \ 其他 \end{cases} f(x,y)=N2u=0N1v=0N1F(u,v)cos(2N2x+1uπ)cos(2N2y+1vπ)    x,y,u,v=0,1,...,N1c(u)=c(v)={2 1  u=0,v=01  
其中 F ( u , v ) F(u,v) F(u,v)为频域函数, f ( u , v ) f(u,v) f(u,v)为空域函数。

算法思路

水印嵌入算法

下列为 m × n m\times n m×n的灰度图原始载体图像和 k × h k\times h k×h的二值水印图像的水印嵌入过程。

  1. 将水印图像n次置乱处理得到置乱后的水印 矩阵 W 0 W_0 W0.
  2. 将 载 体 图 像分 为 k × h k\times h k×h个 子 块 ,对 每 个 子 块 做 DCT 变换,得到每个子块的DCT系数矩阵 C { i , j } C\{i,j\} C{i,j} i 、 j i、j ij 表示第i行第j列的子块, 1 ≤ i ≤ m , 1 ≤ j ≤ n 1≤i≤m,1≤j≤n 1im,1jn.
  3. 对每个子块 C { i , j } C\{i,j\} C{i,j}做奇异值分解 C { i , j } = U S V T C\{i,j\}=USV^T C{i,j}=USVT, 得到 U , S , V U,S,V U,S,V.
  4. 取一常数 q q q作为嵌入系数,将 S S S中的第一项 S ( 1 , 1 ) S(1,1) S(1,1) q q q相除得到的余数为 z z z。若 W 0 ( i , j ) W_0(i,j) W0(i,j)的值为1,则将 S ( 1 , 1 ) S(1,1) S(1,1)修改成 S ( 1 , 1 ) − z + q S(1,1)-z+q S(1,1)z+q;若 W 0 ( i , j ) W_0(i,j) W0(i,j)值 为0,则 S ( 1 , 1 ) S(1,1) S(1,1)变为 S ( 1 , 1 ) − z + 0.5 q S(1,1)-z+0.5q S(1,1)z+0.5q.
  5. 用水印信息修改后 S ′ S^′ S构造新的矩阵 C { i , j } = U S ′ V T C\{i,j\}=US^′V^T C{i,j}=USVT.
  6. 将每个新修改的 C { i , j } C\{i,j\} C{i,j}分别做DCT逆变换,再合并为一个整图,即得到嵌入水印的新图像。

水印提取算法

  1. 将嵌入水印的图像分成 k × h k\times h k×h个子块并对每个子块做DTC变换,得到每个子块DCT系数 C ′ ′ { i , j } C^{''}\{i,j\} C{i,j} 1 ≤ i ≤ m , 1 ≤ j ≤ n 1≤i≤m,1≤j≤n 1im,1jn;
  2. 对每个子块 C i ′ ′ Ci^{′′} Ci进行奇异值分解 C ′ ′ { i , j } = U ′ ′ S ′ ′ V ′ ′ T C^{''}\{i,j\}=U^{′′}S^{′′}V^{′′T} C{i,j}=USVT,得到 S ′ ′ S^{′′} S.
  3. 比较 S ′ ′ ( 1 , 1 ) S^{′′}(1,1) S(1,1)与嵌入系数q的大小,若比0大,则提取水印矩阵 W 0 ′ = 0 W_0^′=0 W0=0,否则 W 0 ′ = 1 W_0^′=1 W0=1.
  4. 对提取的 W 0 ′ W_0^′ W0进行反置乱,即得到提取出的水印图像。

代码实现

下面代码的重要前提条件是:载体图像的长宽能被水印图像的长宽整除,否则就会出现bug。

clear;
img = imread("Always like this.png");
watermark = double(imread('watermark.png'));
img_grayed = double(rgb2gray(img));
key = 10; % key是对watermark进行Arnold置乱的次数
a = 1;b = 1;
[prow, pcol] = size(img_grayed);
[wrow, wcol] = size(watermark);
% 进行arnold置乱
watermark_arnolded = zeros(wrow, wcol);
for i = 1:key
    for y = 1:wrow
        for x = 1:wcol
            xx = mod((x-1)+b*(y-1), wrow)+1;
            yy = mod(a*(x-1)+(a*b+1)*(y-1), wrow)+1;
            watermark_arnolded(yy, xx) = watermark(y, x);
        end
    end 
    watermark = watermark_arnolded;
end 
%% 嵌入水印
img_block = mat2cell(img_grayed, (prow/wrow)*ones(1, wrow), (pcol/wcol)*ones(1, wcol));
q = 0.5;
img_res = zeros(prow, pcol);
for i = 1:wrow
    for j = 1:wcol
        temp_matrix = dct2(cell2mat(img_block(i, j)));
        [U, S, V] = svd(temp_matrix);
        z = rem(S(1, 1), q);
        if watermark_arnolded(i, j) == 1
            S(1, 1) = S(1, 1)-z+q;
        elseif watermark_arnolded(i, j) == 0
            S(1, 1) = S(1, 1)-z+0.5*q;
        end
        temp_matrix = U*S*V';
        temp_matrix = idct2(temp_matrix);
        for k = 1:(prow/wrow)
            for h = 1:(pcol/wcol)
                img_res((i-1)*(prow/wrow)+k, (j-1)*(pcol/wcol)+h) = temp_matrix(k, h);
            end
        end
    end
end
subplot(1, 3, 1);
imshow(uint8(img_res));
title('加入水印后的图像') ;
%% 对水印进行提取
img_block = mat2cell(img_res, (prow/wrow)*ones(1, wrow), (pcol/wcol)*ones(1, wcol));
watermark_recovery = zeros(wrow, wcol);
for i = 1:wrow
    for j=1:wcol
        temp_matrix = cell2mat(img_block(i, j));
        temp_matrix = dct2(temp_matrix);
        [U, S, V] = svd(temp_matrix);
        if rem(S(1, 1), q) > 0
            watermark_recovery(i, j) = 0;
        else
            watermark_recovery(i, j) = 1;
        end
    end
end
subplot(1, 3, 2);
imshow(watermark_recovery);
title('提取出的水印图像');
%% 对水印反置乱
a = 1;b = 1;
key = 10;
watermark_res = zeros(wrow, wcol);
for i = 1:key
    for y = 1:wrow
        for x = 1:wcol
            xx=mod((a*b+1)*(x-1)-b*(y-1), wrow)+1;
            yy=mod(-a*(x-1)+(y-1), wrow)+1;
            watermark_res(yy, xx) = watermark_recovery(y, x);
        end
    end 
    watermark_recovery = watermark_res;
end
figure(3);
imshow(watermark_res);
title('反置乱之后的水印图像');

运行结果

基于奇异值分解的图像压缩和信息隐藏_第3张图片

可以看到反置乱之后的水印充满各种噪点,经过python.cv2简单降噪之后手机仍然无法识别二维码,噪点出现的原因暂时不知道。(以后可能会解决?)

参考文献

[1]刘瑞祯,谭铁牛.基于奇异值分解的数字图像水印方法[J].电子学报,2001(02):168-171.

[2]丁珊,张定会,周雄葵.一种基于离散余弦变化和奇异值分解的数字水印算法[J].数据通信,2015(04):51-54.

你可能感兴趣的:(实验报告,笔记,matlab,图像处理)