首页 文章详情

MatLab 图像处理 || 一次畅快的图像水印系统嵌入提取评价过程~~

新机器视觉 | 880 2022-07-08 17:49 0 0 0
UniSMS (合一短信)

点击下方卡片,关注“新机器视觉”公众号

重磅干货,第一时间送达

 是的,这我们这次真的好见了,各位撇学生 。

作为一个图像处理领域的老饕,很久没有更新和图像处理相关的知识了。刘老师的风格你们懂得,要么更新一次完整的,要么不更新。

这次带来的项目是印刷图像的水印嵌入与提取。
为什么要加水印:当然是防盗、版权意识。
其实这是一个很简单项目,奈何系统的介绍很少,因此我决定整理一下之前的代码。做成一个系统的推文供大家参考。

老规矩:本次代码依旧放在我的Github上:
https://github.com/ImageVisioner/Watermark_System_In_Matlab

通过本推文,您能学到图像处理的所有基本操作,与相关的信号处理操作。在具体讲解之前需要各位了解一下一些基本常识。

印刷领域一般使用*.tif/*.tiff格式保存图像,TIFF 以任何颜色深度存储单个光栅图像。为什么不使用*.jpg作为图像印刷的格式,是因为jpg易产生杂边,杂点,并且会压缩数据点、产生色差。反正记住、高档印刷都是*.tif/*.tiff。
因此我这里有两张印刷格式的图像:
看看其图像信息:
这两张印刷图像就是我们将被嵌入的图像,我们称之为宿主图像(host image)或者载体图像。正如生物链一般,有宿主就会有寄生。在图像处理中,我们将其成为水印图像(cover image)。

因此介绍一下我们本次的水印图像:
因此本文的任务就是将“M”类型的图像嵌入到宿主图像之中
那我们开始吧~

宿主图像的格式更换

读入图像:
filepath='N1A.TIF';file=imread(filepath)
但是对于印刷图像,对于使用tiff格式之外,为了保证颜色的不失真,通常采用CMYK颜色空间模式。CMYK是印刷四色模式,它利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓"全彩印刷"

不过Matlab中对于CMYK或者lab色彩空间无法直接进行操作,需要进行转换为RGB色彩空间后进行操作。在Matlab中使用makecform函数可以对颜色空间进行无损转换。
makecform函数支持由国际照明委员会(国际照明委员会或 CIE)makecform定义的与设备无关的色彩空间系列成员之间的转换。还支持与 sRGB和CMYK颜色空间之间的转换。
CC = makecform('cmyk2srgb'); %srgb(标准rgb)I_rgb = applycform(file,CC);
因此我们可以通过此标准将CMYK色彩空间图像转换到RGB空间下。

整体流程技术路线

既然已经学会了如何读取和转换图像,那么简单的介绍一下整个的水印技术路线是如何的。这路线不会有人看不懂吧。


 宿主图像的分解

Matlab默认是RGB颜色空间,通过对单个空间进行单独嵌入水印后,进行通道叠加,会有更稳定的效果。
提取宿主图像的RGB三个通道,代码如下:
I_rgb_R=I_rgb(:,:,1); %RED通道I_rgb_G=I_rgb(:,:,2); %GREEN通道I_rgb_B=I_rgb(:,:,3); %Blue通道

 嵌入图像设计算法

此部分分为两个部分进行进行,1、对宿主图像进行DWT+SVD解,保证嵌入的稳定性 2、对水印图像进行置乱,保证水印图像不被破解。

  • 对宿主图像进行操作

其中DWT(Discrete Wavelet Transform),为离散小波分解,是信号处理中对矩阵的一种分解形式。
若对一张图像进行DWT分解,能得到四个信息A是低频信息,H是水平高频信息,V是垂直高频信息、D是对角高频信息。其中A中低频部分存储这大部分的能量,包含了图像的大量信息。

由于A中低频部分存储这大部分的能量,因此考虑在分解出的A矩阵中进一步SVD分解。用来保证破解难度。SVD原理如下链接解释:
https://heleifz.github.io/15084626290253.html

SVD分解简图:

篇幅有限给出部分代码,完整代码函数请参考Github上:

[w_LL,w_LH,w_HL,w_HH]=dwt2(watermark,'haar');img_water=w_LL;Red_water=img_water(:,:,1);Green_water=img_water(:,:,2);Blue_water=img_water(:,:,3);%svd分解%分解出幺正矩阵[U_imgr2,S_imgr2,V_imgr2]= svd(Red_water);[U_imgg2,S_imgg2,V_imgg2]= svd(Green_water);[U_imgb2,S_imgb2,V_imgb2]= svd(Blue_water);[h_LL,h_LH,h_HL,h_HH]=dwt2(cover,'haar');
  • 对水印图像进行操作

function arnoldImg = arnold(massage,a,b,n)%猫脸置乱算法%img 灰度图像 a,b为参数 n为变换次数[height,weight] = size(massage);N=height;arnoldImg = zeros(height,weight);for i=1:n for y=1:height for x=1:weight %防止取余过程中出现错误,先把坐标系变换成从0 到 N-1 xx=mod((x-1)+b*(y-1),N)+1; yy=mod(a*(x-1)+(a*b+1)*(y-1),N)+1; arnoldImg(yy,xx)=massage(y,x); end end massage=arnoldImg;endarnoldImg = uint8(arnoldImg);end
置乱十次之后的水印图像效果

宿主图像嵌入的结果:


水印提取图像设计算法

水印的提取与嵌入互为逆过程,核心代码如下,完整代码如Githubs所示:

function ExactImage=exact(cover,watermark,watermarked)
[U_imgr1,S_imgr1,V_imgr1]= svd(red1);[U_imgg1,S_imgg1,V_imgg1]= svd(green1);[U_imgb1,S_imgb1,V_imgb1]= svd(blue1);

%watermark[w_LL,w_LH,w_HL,w_HH]=dwt2(watermark,'haar');img_wat=w_LL;%分离通道提取red2=img_wat(:,:,1);green2=img_wat(:,:,2);blue2=img_wat(:,:,3);[U_imgr2,S_imgr2,V_imgr2]= svd(red2);[U_imgg2,S_imgg2,V_imgg2]= svd(green2);[U_imgb2,S_imgb2,V_imgb2]= svd(blue2);
%watermarked[wm_LL,wm_LH,wm_HL,wm_HH]=dwt2(watermarked,'haar');img_w=wm_LL;red3=img_w(:,:,1);green3=img_w(:,:,2);blue3=img_w(:,:,3);
[U_imgr3,S_imgr3,V_imgr3]= svd(red3);[U_imgg3,S_imgg3,V_imgg3]= svd(green3);[U_imgb3,S_imgb3,V_imgb3]= svd(blue3);

S_ewatr=(S_imgr3-S_imgr1)/0.01;S_ewatg=(S_imgg3-S_imgg1)/0.01;S_ewatb=(S_imgb3-S_imgb1)/0.01;
ewatr = U_imgr2*S_ewatr*V_imgr2';ewatg = U_imgg2*S_ewatg*V_imgg2';ewatb = U_imgb2*S_ewatb*V_imgb2';end
从下图可以看出,左边为原图水印,右边为提取出的水印,由于各种嵌入和分解的限制,导致会出现噪声和干扰的情况。见箭头的方框图位置。属于正常现象,任何水印的提取都无法达到无损提取的状况。


 图像的攻击评价

对于一个鲁棒性的算法,我们需要对其多种攻击试验,才能验证其算法的稳定性,因此在水印算法中,有如下的测试算法稳定性的方式。


目前常用的攻击有:滤波攻击(高斯滤波、中值滤波)、声攻击(椒盐噪声、高斯噪声)和剪切等攻击方式。

书写自定义函数AttackImage,其中cover参数为宿主图像,k为攻击方式:其中本函数预设了五钟攻击方式如下所示,各位可以根据自己的喜好,自行添加各种的图像攻击算法,在这里就不一一进行列举。
function Attackimg=AttackImage(cover,k)cover=uint8(cover);if k==1    noise=randn(size(cover))*100;    noise=uint8(noise);    cover=cover+noise;    Attackimg=cover;    elseif k==2     %高斯滤波攻击    w= fspecial('gaussian',[7,7],1);    cover=imfilter(cover,w,'replicate');    Attackimg=cover;elseif k==3  %均值    Average=fspecial('average',[13,13]);    cover=imfilter(cover,Average);    Attackimg=cover;    elseif k==4  %并且剪切    [m,n]=size(cover);    cover_r=cover(:,:,1);    cover_r(1:m/3,1:n/3)=256;    cover_g=cover(:,:,2);    cover_g(1:m/3,1:n/3)=256;    cover_b=cover(:,:,3);    cover_b(1:m/3,1:n/3)=256;    %合并    cover(:,:,1)=cover_r;    cover(:,:,2)=cover_g;    cover(:,:,3)=cover_b;    Attackimg=cover;elseif k==5    %旋转攻击    cover=imrotate(cover,30,'bilinear','crop');    Attackimg=cover;else    Attackimg=cover;endend

在使用AttackImage函数对嵌入水印后的宿主图像进行攻击,判断攻击后的前后图像的差异性。
其中
MSE:均方差误差,反映了图像像素值与均值的离散程度,标准差越⼤说明图像的质量越好(说明图像边缘清晰)。

PSNR:峰值信噪比,是一种评价图像的客观标准,它具有局限性,一般是用
于最大值信号和背景噪音之间的一个工程项目。
NcValue:相关系数,用来衡量两个图像之间的相似程度。

根据上述公式书写代码,由于篇幅限制,完整的代码放在Github上。下列代码只给出核心代码区域。
function [MSE,PSNR,NcValue] =ImageEvaluation(cover,EmbedImage)  %%具体代码GitHub   psnr_red=10*log10(255^2/MSE_RED);  %红色通道的psnr  psnr_green=10*log10(255^2/MSE_Green); %绿色通道的psnr  psnr_blue=10*log10(255^2/MSE_Blue);       MSE=(MSE_Blue+MSE_Green+MSE_RED)/3;    PSNR=(psnr_blue+psnr_red+psnr_green)/3;      %如果变成灰度图 那么两幅图相等 得到的Ncvalue为NAN        %必须为二维数组    cover_gray=rgb2gray(cover);   EmbedImage_gray=rgb2gray(EmbedImage);   NcValue1=corr2(cover_gray,EmbedImage_gray);  disp(NcValue1)  %内部进行打印       %将其转换到各个通道计算  NcValue_Red=corr2(cover_red,Embed_red);              NcValue_Blue=corr2(cover_blue,Embed_blue); NcValue_green=corr2(cover_green,Embed_green);   NcValue=(NcValue_Red+NcValue_Blue+NcValue_green)/3; end
查看结果:

【注意】:MSE越小,则PSNR越大;所以PSNR越大,代表着图像质量越好。PSNR值高于40dB说明图像质量极好(即非常接近原始图像),在30—40dB通常表示图像质量是好的(即失真可以察觉但可以接受)在20—30dB说明图像质量差。PSNR低于20dB图像不可接受,一般来说NC系数在±1之间 ,其绝对值靠近1为两者的相关性强。

 图像的一些小修补

经历过水印嵌入的图像,在亮度上会发生些许改变,因此我们需要对其图像的亮度进行归一化处理。
嵌入水印后的图像,明显看到左右图像会有亮度色差的差异。
function BrightnesImage=EqualBrightness(cover,EmbedImage)%亮度规格化算法%cover为载体图像%EmbedImage为嵌入水印的照片 aa=mean2(rgb2gray(cover)); bb=mean2(rgb2gray(EmbedImage)); BrightnesImage=EmbedImage+abs((aa-bb));end


本次项目,没有给同学们阐述盲水印 最小位数嵌入水印这种概念,只是从基本的思路给大家阐述了如何嵌入。各位若想了解更多数字水印的基本概念。可以多去看看文献和论文,不是很难,难在如何用代码表达。

老规矩:本次代码依旧放在我的Github上:
https://github.com/ImageVisioner/Watermark_System_In_Matlab
使用方式,运行主函数main即可。
                         

本文仅做学术分享,如有侵权,请联系删文。

—THE END—
good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter