基于DCT变换(变换域)实现信息隐藏(数字水印)原理详解及matlab实现

主要就是实现了数字水印的嵌入提取和在不同攻击如旋转剪切噪声等下的提取效果差异的比对

1 DCT变换的原理

2  DCT变换的特点

    在基于DCT的变换编码中,图像是先经分块(8×8或16×16)后再经DCT,这种变换是局部的,只反映了图像某一部分的信息。当然也可以对整幅图像的特点,但是运算速度比分块DCT要慢。图像经DCT后,得到的DCT图像有三个特点:  

    (1). 系数值全部集中到0值附近(从直方图统计的意义上),动态范围很小,这说明用较小的量化比特数即可表示DCT系数; 

    (2). DCT变换后图像能量集中在图像的低频部分,即DCT图像中不为零的系数大部分集中在一起(左上角),因此编码效率很高。 

    (3). 没有保留原图像块的精细结构,从中反映不了原图像块的边缘、轮廓等信息,这一特点是由DCT缺乏时局域性造成的。

3 宿主图像的DCT变换

对于N×N大小的256灰度级的宿主图像I进行N×N二维离散余弦变换(DCT)。以ZigZag方式对于DCT变换后的图像频率系数重新排列成一维向量Y={y1, y2,…yN×N}.  并取出序列中第L+1到L+M的中频系数部分,得到YL={ YL+1, YL+2,…, YL+M}。

4 DCT数字水印嵌入算法流程


5.DCT数字水印提取算法流程



matlab代码实现:

DCT主函数

%------------------------------------------------------------------%
%     基于DCT变换的信息隐藏(数字水印)     %%                                                                %%                                                                %
%-----------------------------------------------------------=------%
clear ;
clc;
      
%-----------------------读入图像-------------------------------------%
markbefore=imread('sss.bmp');
markbefore2=rgb2gray(markbefore);
mark=im2bw(markbefore2);    %使水印图像变为二值图
figure(1);      %打开窗口
subplot(2,3,1);    %该窗口内的图像可以有两行三列
imshow(mark),title('水印图像');   %显示水印图像
[rm,cm]=size(mark);   %计算水印图像的长宽

cover_image=imread('carrier_image.bmp');
cover_image=rgb2gray(cover_image);
subplot(2,3,2),imshow(cover_image,[]),title('载体图像'); %[]表示显示时灰度范围为image上的灰度最小值到最大值

before=blkproc(cover_image,[8 8],'dct2');   %将载体图像的灰度层分为8×8的小块,每一块内做二维DCT变换,结果记入矩阵before

I=mark;
alpha=30;     %尺度因子,控制水印添加的强度,决定了频域系数被修改的幅度
k1=randn(1,8);  %产生两个不同的随机序列
k2=randn(1,8);
after=before;   %初始化载入水印的结果矩阵
for i=1:rm          %在中频段嵌入水印
    for j=1:cm
        x=(i-1)*8;
        y=(j-1)*8;
        if mark(i,j)==1
            k=k1;
        else
            k=k2;
        end;
        after(x+1,y+8)=before(x+1,y+8)+alpha*k(1);
        after(x+2,y+7)=before(x+2,y+7)+alpha*k(2);
        after(x+3,y+6)=before(x+3,y+6)+alpha*k(3);
        after(x+4,y+5)=before(x+4,y+5)+alpha*k(4);
        after(x+5,y+4)=before(x+5,y+4)+alpha*k(5);
        after(x+6,y+3)=before(x+6,y+3)+alpha*k(6);
        after(x+7,y+2)=before(x+7,y+2)+alpha*k(7);
        after(x+8,y+1)=before(x+8,y+1)+alpha*k(8);
    end;
end;
result=blkproc(after,[8 8],'idct2');    %将经处理的图像分为8×8的小块,每一块内做二维DCT逆变换
result = uint8(result);
imwrite(result,'markresule.bmp','bmp');      %存储添加水印后的图像
subplot(2,3,3),imshow(result,[]),title('嵌入水印的图像');    %显示添加水印后的图像

%定义一个空空间来存储提取的水印
disp('请选择对图像的攻击方式:');
disp('1.添加白噪声');
disp('2.高斯低通滤波处理');
disp('3.对图像进行部分剪切');
disp('4.将图像旋转十度');
disp('5.将图像压缩处理');
disp('6.添加椒盐噪声');
disp('7.不处理图像,直接显示提取水印');
disp('输入其它数字则直接显示提取水印');
choice=input('请输入选择:');
figure(1);
switch choice        %读入输入的选择  withmark为等待提取水印的图像
    case 1
        result_1=result;
        withmark=imnoise(result_1,'gaussian',0.02); %加入椒盐躁声
        subplot(2,3,4);
        imshow(withmark,[]);
        title('加入高斯白噪声后的图像');     %显示加了椒盐噪声的图像
    case 2
         result_2=result;
         H=fspecial('gaussian',[4,4],0.2); 
         result_2=imfilter(result_2,H); 
         subplot(2,3,4); 
         imshow(result_2,[]); 
         title('高斯低通滤波后图像'); 
         withmark=result_2;
    case 3
        result_3=result;
        result_3(1:64,1:400)=512;   %使图像上方被剪裁
        subplot(2,3,4);
        imshow(result_3);
        title('上方剪切后图像');
        withmark=result_3;
    case 4
        result_4=imrotate(result,10,'bilinear','crop');   %最邻近线性插值算法旋转10度
        subplot(2,3,4);
        imshow(result_4);
        title('旋转10度后图像');
        withmark=result_4;
    case 5
        result_5 = result; 
        result_5=im2double(result_5); 
        cnum=10; 
        dctm=dctmtx(8); 
        P1=dctm; 
        P2=dctm.'; 
        imageDCT=blkproc(result_5,[8,8],'P1*x*P2',dctm,dctm.'); 
        DCTvar=im2col(imageDCT,[8,8],'distinct').'; 
        n=size(DCTvar,1); 
        DCTvar=(sum(DCTvar.*DCTvar)-(sum(DCTvar)/n).^2)/n; 
        [dum,order]=sort(DCTvar); 
        cnum=64-cnum; 
        mask=ones(8,8); 
        mask(order(1:cnum))=zeros(1,cnum); 
        im88=zeros(9,9); 
        im88(1:8,1:8)=mask; 
        im128128=kron(im88(1:8,1:8),ones(16)); 
        dctm=dctmtx(8); 
        P1=dctm.'; 
        P2=mask(1:8,1:8); 
        P3=dctm; 
        result_5=blkproc(imageDCT,[8,8],'P1*(x.*P2)*P3',dctm.',mask(1:8,1:8),dctm); 
        WImage5cl=mat2gray(result_5); 
        subplot(2,3,4); 
        imshow(WImage5cl); 
        title('经JPEG压缩后图像'); 
        withmark=WImage5cl;
    case 6
        result_6=result;
        withmark=imnoise(result_6,'salt & pepper',0.02); %加入椒盐躁声
        subplot(2,3,4);
        imshow(withmark,[]);
        title('加入椒盐噪声后的图像');     %显示加了椒盐噪声的图像
    case 7
        subplot(2,3,4);
        imshow(result,[]);
        title('未受攻击的水印图像');
        withmark=result;
    otherwise
        disp('输入数字选择无效,图像未受攻击,直接提取水印');
        subplot(2,3,4);
        imshow(result,[]);
        title('未受攻击的水印图像');
        withmark=result;
end

%------------------------水印提取-----------------------------%
%
after_2=blkproc(withmark,[8,8],'dct2');   %此步开始提取水印,将灰度层分块进行DCT变换
p=zeros(1,8);        %初始化提取数值用的矩阵
mark_2 = zeros(rm,cm);
for i=1:rm
    for j=1:cm
        x=(i-1)*8;y=(j-1)*8;
        p(1)=after_2(x+1,y+8);         %将之前改变过数值的点的数值提取出来
        p(2)=after_2(x+2,y+7);
        p(3)=after_2(x+3,y+6);
        p(4)=after_2(x+4,y+5);
        p(5)=after_2(x+5,y+4);
        p(6)=after_2(x+6,y+3);
        p(7)=after_2(x+7,y+2);
        p(8)=after_2(x+8,y+1);
        if corr2(p,k1)>corr2(p,k2)  %corr2计算两个矩阵的相似度,越接近1相似度越大
            mark_2(i,j)=1;              %比较提取出来的数值与随机频率k1和k2的相似度,还原水印图样
        else
            mark_2(i,j)=0;
        end
    end
end
subplot(2,3,5);
mark_2 = uint8(mark_2);
imshow(mark_2,[]),title('提取出的水印');
subplot(2,3,6);
imshow(mark),title('原嵌入水印');
NC=correlation(mark_2,mark);  
disp('原水印图像与提取水印图像互相关系数:')
disp(NC);
correlation函数:
function N=correlation(mark_get,mark_prime) 
mark_get=double(mark_get); 
mark_prime=double(mark_prime); 
if size(mark_get)~=size(mark_prime) 
    error('Input vectors must  be the same size!') 
else 
    [m,n]=size(mark_get); 
    fenzi=0; 
    fenmu=0; 
    for i=1:m 
        for j=1:n 
            fenzi=fenzi+mark_get(i,j)*mark_prime(i,j); 
            fenmu=fenmu+mark_prime(i,j)*mark_prime(i,j); 
        end 
    end 
N=min(fenzi/fenmu,fenmu/fenzi); 
end
其中的一个效果图

  • 66
    点赞
  • 420
    收藏
    觉得还不错? 一键收藏
  • 102
    评论
这里提供一个基于DWT信息隐藏算法的Python代码实现,具体实现过程如下: 1. 对原始图像进行DWT变换,得到DWT系数矩阵。 2. 将要隐藏的信息二进制化,并将其嵌入到DWT系数矩阵的低频分量中。 3. 对嵌入了信息的DWT系数矩阵进行IDWT变换,得到隐藏信息后的图像。 4. 将隐藏信息后的图像保存。 代码如下: ``` import cv2 import numpy as np from matplotlib import pyplot as plt def dwt2(src): h, w = src.shape dst = np.zeros((h, w), dtype=np.float32) for i in range(h // 2): for j in range(w // 2): row = i * 2 col = j * 2 a = src[row, col] b = src[row, col + 1] c = src[row + 1, col] d = src[row + 1, col + 1] dst[i, j] = (a + b + c + d) / 4 dst[i + h // 2, j] = (a - b + c - d) / 4 dst[i, j + w // 2] = (a + b - c - d) / 4 dst[i + h // 2, j + w // 2] = (a - b - c + d) / 4 return dst def idwt2(src): h, w = src.shape dst = np.zeros((h, w), dtype=np.float32) for i in range(h // 2): for j in range(w // 2): row = i * 2 col = j * 2 a = src[i, j] b = src[i + h // 2, j] c = src[i, j + w // 2] d = src[i + h // 2, j + w // 2] dst[row, col] = a + b + c + d dst[row, col + 1] = a + b - c - d dst[row + 1, col] = a - b + c - d dst[row + 1, col + 1] = a - b - c + d return dst def hide_info(img_path, msg): img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) h, w = img.shape # DWT变换,得到DWT系数矩阵 dwt_img = img.copy().astype(np.float32) for i in range(int(np.log2(h))): dwt_img[:h // 2, :w // 2] = dwt2(dwt_img[:h // 2, :w // 2]) dwt_img[:h // 2, w // 2:] = dwt2(dwt_img[:h // 2, w // 2:]) dwt_img[h // 2:, :w // 2] = dwt2(dwt_img[h // 2:, :w // 2]) dwt_img[h // 2:, w // 2:] = dwt2(dwt_img[h // 2:, w // 2:]) h = h // 2 w = w // 2 # 将信息嵌入DWT系数矩阵的低频分量 msg_bin = ''.join(format(ord(c), '08b') for c in msg) msg_len = len(msg_bin) i = 0 for x in range(4): for y in range(4): if i >= msg_len: break dwt_img[x, y] = int(format(int(dwt_img[x, y]), '08b')[:-2] + msg_bin[i:i+2], 2) i += 2 if i >= msg_len: break # IDWT变换,得到隐藏信息后的图像 h, w = img.shape for i in range(int(np.log2(h)), 0, -1): h = h // 2 w = w // 2 dwt_img[:h, :w] = idwt2(dwt_img[:h, :w]) dwt_img[:h, w:] = idwt2(dwt_img[:h, w:]) dwt_img[h:, :w] = idwt2(dwt_img[h:, :w]) dwt_img[h:, w:] = idwt2(dwt_img[h:, w:]) dwt_img = idwt2(dwt_img) dwt_img = np.clip(dwt_img, 0, 255).astype(np.uint8) # 保存隐藏信息后的图像 cv2.imwrite('hide_info.jpg', dwt_img) if __name__ == '__main__': hide_info('lena.jpg', 'Hello, World!') ``` 该代码实现了对一张lena图像进行信息隐藏,并在低频分量中嵌入了字符串"Hello, World!"。运行后会在代码所在目录下生成一个名为"hide_info.jpg"的图像文件,即隐藏信息后的图像。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值