天天看点

【语音隐写】基于matlab GUI DCT音频数字水印嵌入提取【含Matlab源码 837期】

一、离散小波变换的音频信号数字水印技术简介

​0 引言​

近年来, 数字水印技术的作用越来越重要。数字水印技术是将一些标识信息直接嵌入数字载体当中, 或间接表示在信号载体中, 且不影响原载体的使用价值。通过隐藏在载体中的这些信息, 可以判断信息是否被篡改, 具有防伪溯源、保护信息安全、版权保护等作用。对于广播转播台站而言, 是广播音频的中转站, 在广播信号发送至千家万户之前务必保证信号的安全可靠, 但现在的大部分台站只是利用人耳的判断, 以及不同信源之间的比较, 具有较大的局限性。若利用数字水印的特性, 应用于广播节目中可以有效地防止信号插播, 可靠地保护信号安全, 保障广播的安全播出。

​1 音频数字水印技术分类​

根据数字水印在音频信号中的处理技术, 可将数字水印分为时域、变换域、压缩域数字水印。

​1.1 时域数字水印​

在时域数字水印技术中, 直接将水印信息嵌入至音频信号中, 通常会选择隐藏在信号不重要部位, 以保证其嵌入水印不影响原音频信号的监听效果。时域水印技术的实现较为容易且运算量小, 简单直接, 但是鲁棒性差, 容易被破解, 抵抗力较差。

​1.2 变换域数字水印​

在变换域数字水印中, 音频信号需经过时域至变换域的转换, 通常的变换域有离散余弦变换 (DCT, Discrete Cosine Transform) 、离散傅立叶变换 (DFT, Discrete Fourier transform) 、离散小波变换 (DWT, Discrete Wavelet Transform) 等。在变换域中嵌入水印信息, 通过反变换得到嵌入水印的音频时域信号。变换域水印技术较时域水印技术复杂, 但变换域嵌入的水印信息较时域而言, 不可见性更强, 隐蔽性更好, 鲁棒性更好。本文的研究主要基于DWT的音频信号的水印信息的嵌入与提取。

​1.3 压缩域数字水印​

在时域和变换域的水印技术, 都是直接将水印信号嵌入未压缩的音频格式中, 但是通常在音频信号的传输或存储中需要对音频信号进行压缩编码 (例如WMA、MP3等) , 因此压缩域数字水印也是水印技术也具有较大的实用价值。压缩域数字水印技术大致可分为三类: (1) 在非压缩域嵌入水印, 将音频信号与水印信息一起压缩; (2) 在压缩域中, 直接将水印信息嵌入压缩的音频信号中; (3) 将压缩后的信号进行解压缩, 然后嵌入水印信息, 最后将水印信息和解压后的音频信号一起压缩。总的来说, 压缩域水印技术的编解码系统过于复杂, 受压缩编码格式限制大, 压缩后的音频信号已经去除了冗余, 因此加入水印的难度大, 压缩域水印技术有待进一步研究。

二、部分源代码

function varargout = main(varargin)
% MAIN MATLAB code for main.fig
%      MAIN, by itself, creates a new MAIN or raises the existing
%      singleton*.
%
%      H = MAIN returns the handle to a new MAIN or the handle to
%      the existing singleton*.
%
%      MAIN('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in MAIN.M with the given input arguments.
%
%      MAIN('Property','Value',...) creates a new MAIN or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before main_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to main_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help main

% Last Modified by GUIDE v2.5 15-Apr-2021 12:58:02

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @main_OpeningFcn, ...
    'gui_OutputFcn',  @main_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before main is made visible.
function main_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to main (see VARARGIN)

% Choose default command line output for main
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes main wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = main_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
addpath('.\wavelet\')%添加小波变换工具箱
%% 选择音频
[file1,pathname]=uigetfile('*.wav','请选择要识别的样本');%跳出对话框
fname=fullfile(pathname,file1);%音频文件名
[X,fs]=audioread(fname); %读入音频文件
s=get(handles.popupmenu1,'Value'); 

handles.axes1 %选定坐标轴1
subplot(2,2,1); %子窗口
plot(X);     %显示音频文件波形
title('原始音频信号');
handles.X=X;%保存原始音频信号
handles.fs=fs;%保存原始音频信号频率
handles.s=s;
guidata(hObject, handles);
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
%% 选择水印
[file1,pathname]=uigetfile('*.bmp','请选择要识别的样本');%跳出对话框
fname=fullfile(pathname,file1);%选择图片
key=35;%密钥参数
%Arnold置换次数,作为密钥
Orignalmark=double(imread(fname));  %读入64*64的水印图片
[wrow,wcol]=size(Orignalmark);  %图像大小wrow行,wcol列
if wrow~=wcol
    error('wrow~=wcol error');%如果行列不相等则报错
end
%--- 测试密钥key是否超出范围---------
n=check_arnold(wrow);
if (key+1)>n
    error('arnold key error');
end
s=get(handles.popupmenu1,'Value'); 

subplot(2,2,2); hold on
imshow(Orignalmark),title('原始图像');
handles.Orignalmark=Orignalmark;%保存原始图像
handles.n=n;
handles.s=s;
guidata(hObject, handles);
% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
%% 嵌入水印
%水印嵌入--------------------------------------------------
X=handles.X;%读取音频
Orignalmark=handles.Orignalmark;%读取水印图像
fs=handles.fs;%频率
s=handles.s;%算法类型
[wrow,wcol]=size(Orignalmark);
key=35;%密钥
if s==2
    
    Arnoldw=arnold(Orignalmark,wrow,key); %对水印图像进行Arnold转化
    [c,l]=wavedec(X,2,'db4'); % 
    ca2=appcoef(c,l,'db4',2); % 
    cd2=detcoef(c,l,2);  %  
    cd1=detcoef(c,l,1);  % 
    lca=length(ca2);  %低频长度
    blocksize=fix(lca/(wrow*wcol)); %每块的大小
    water_vector=reshape(Arnoldw,1,wrow*wcol);  %将置乱后的水印转化为一维的
    wlength=wrow*wcol;  %水印的长度
    a=0.25;  %量化步长
    j=1;
    for i=1:wlength
        Block=ca2(j:j+blocksize-1);
        [U,S,V]=svd(double(Block));
        cc=floor(S(1,1)/a);
        if(Arnoldw(i)==1)           %嵌入奇数倍
            if(mod(cc,2)==0)
                cc=cc+1;
            end
            S(1,1)=a*cc;
        end
        if(Arnoldw(i)==0)            %嵌入偶数倍
            if(mod(cc,2)==1)
                cc=cc+1;
            end
            S(1,1)=a*cc;
        end
        Blockw=U*S*V';          % 还原
        ca2(j:j+blocksize-1)=Blockw;
        j=j+blocksize;
    end
    c1=[ca2',cd2',cd1']';
    MarkedX=waverec(c1,l,'db4');%b为量化嵌入水印后的音频数据
else
    A=X;
    L = size(A);% 用变量L存储音频A的长度
    M=Orignalmark;
    BW = im2bw(M);% 将图像Lena.bmp转化为二值图并存入变量BW
    % 计算水印矩阵大小
    [M1,M2] = size(BW);
    % M12为中间变量,避免每次都计算M1*M2
    M12 = M1*M2;
    % 降维,将水印信息得到的一维序列存入序列C中
    C = reshape(BW,1,M12);
    n = M12;
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % 对水印信号进行扩频处理,效果不是很好
    % 扩频系数为2
    n = M12*2;
    M = zeros(n,1);
    % 产生密钥序列M
    for k = 1 : n
        if mod(k,4) == 0
            M(k) = 1;
        else
            M(k) = 0;
        end
        % 水印信号序列分别按位与密钥异或
        l = ceil(k/2);
        S(k) = bitxor(C(l),M(k));
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % 嵌入一个水印信息需要的音频数据为N
    N = 10;
    length1 = n*10;
    % 将原始音频信号分解为Ae和Ar两部分
    i = 1 : length1;
    j = [1];
    % 取矩阵A的l到length行构建矩阵Ae
    Ae = A(i,j);
    % Ae(i,j)
    i = length1+1 : L;
    % 取矩阵A的length到L行第一列构建矩阵Ar
    Ar = A(i,j);
    
    
    % 建立元胞B,每个音频数据段Ae(m)是B的一个元素
    k = 1;
    % 建立M1 x M2行l列的元胞
    B = cell(n,1);
    th = n*N;
    % 当k小于Ae的长度时,矩阵Ae每10行作为一个音频数据段存入元胞B中
    while ( k < th )
        i = k : k+9;
        m = (k+9)/10;
        B{m,1} = Ae(i,j);
        k = k+10;
    end      

三、运行结果

【语音隐写】基于matlab GUI DCT音频数字水印嵌入提取【含Matlab源码 837期】

四、matlab版本及参考文献

​1 matlab版本​

2014a

​2 参考文献​

[1]韩纪庆,张磊,郑铁然.语音信号处理(第3版)[M].清华大学出版社,2019.

继续阅读