【图像隐写】基于DWT、SVD和扩频技术混合可见-隐形水印系统(将彩色标志和强大的隐藏水印嵌入图像中附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、算法改进、程序设计科研仿真。
🍎完整代码获取 定制创新 论文复现私信
🍊个人信条:做科研,博学之、审问之、慎思之、明辨之、笃行之,是为:博学慎思,明辨笃行。
🔥 内容介绍
一、引言
在当今数字化信息时代,图像作为信息传播的重要载体,其版权保护和信息安全至关重要。混合可见 - 隐形水印系统通过将彩色标志和强大的隐藏水印嵌入图像,既能直观地展示版权信息,又能在需要时通过特定手段提取隐藏信息,为图像保护提供了双重保障。离散小波变换(DWT)、奇异值分解(SVD)和扩频技术的结合,为构建这样一个高效、鲁棒的水印系统奠定了基础。
二、相关技术原理
离散小波变换(DWT):DWT 将图像分解为不同频率子带,包括近似子带(低频部分)和细节子带(高频部分)。低频子带保留了图像的主要能量和大部分视觉信息,而高频子带包含图像的边缘、纹理等细节信息。通过对图像进行 DWT 分解,可以在不同频率子带上进行水印嵌入操作,利用低频子带的稳定性来提高水印的鲁棒性,利用高频子带的细节特性来保证水印的不可见性。
奇异值分解(SVD):SVD 是一种矩阵分解技术,对于任意矩阵 A,可以分解为 A=UΣVT,其中 U 和 V 是正交矩阵,Σ 是对角矩阵,其对角元素为奇异值。奇异值反映了矩阵的固有特征,在图像中,奇异值对图像的光照、几何变换等具有较好的稳定性。将水印信息嵌入到图像的奇异值中,可以使水印在经历多种图像处理操作后仍能被准确提取。
扩频技术:扩频技术通过将原始水印信号扩展到一个更宽的频带,使其能量分散在整个频带内,从而增强水印的抗干扰能力。在水印嵌入过程中,将水印信号与一个伪随机序列(扩频码)相乘,实现频谱扩展。接收端使用相同的扩频码对含水印图像进行相关运算,以提取水印。扩频技术能够有效抵抗噪声、滤波等常见攻击,提高水印系统的鲁棒性。
三、混合可见 - 隐形水印系统的实现
彩色标志嵌入(可见水印):
图像预处理:将彩色标志图像转换为与宿主图像相同的色彩空间(如 RGB),并调整其大小与宿主图像适配。
DWT 分解:对宿主图像和彩色标志图像分别进行 DWT 分解,得到不同频率子带。
水印嵌入:选择宿主图像的低频子带,利用 SVD 将其分解为 UΣVT。对彩色标志图像的低频子带进行类似处理,得到其奇异值矩阵 Σw。将 Σw 与 Σ 按一定规则融合(如相加或加权相加),得到新的奇异值矩阵 Σ′。通过逆 SVD 操作,将 UΣ′VT 重构为低频子带,再进行逆 DWT 变换,得到嵌入彩色标志的图像。
隐藏水印嵌入(隐形水印):
水印生成与扩频:生成二进制隐藏水印信息,通过扩频技术将其与伪随机扩频码相乘,得到扩频后的水印信号。
DWT 分解:对宿主图像再次进行 DWT 分解,选择部分细节子带(如水平、垂直和对角细节子带)。
水印嵌入:对所选细节子带进行 SVD 分解,将扩频后的水印信号嵌入到奇异值中(例如,通过调整奇异值的大小来嵌入水印信息)。完成嵌入后,通过逆 SVD 和逆 DWT 变换,得到嵌入隐藏水印的图像。
水印提取:
彩色标志提取(可见水印):对含水印图像进行 DWT 分解,提取低频子带并进行 SVD 分解。根据嵌入规则,从奇异值矩阵中分离出彩色标志的奇异值矩阵,通过逆 SVD 和逆 DWT 变换,重构彩色标志图像。
隐藏水印提取(隐形水印):对含水印图像进行 DWT 分解,提取嵌入隐藏水印的细节子带并进行 SVD 分解。根据嵌入的扩频水印信号与扩频码的相关性,通过相关运算提取隐藏水印信息。在提取过程中,需要考虑到可能存在的噪声和图像处理操作对水印的影响,通过适当的阈值设定和信号处理方法,准确恢复隐藏水印。
⛳️ 运行结果
📣 部分代码
%% extract_invisible_hybrid.m
% Extraction of Invisible DWT LL-band Watermark + Validity Metrics
clc; clear; close all;
%% PARAMETERS (must match embedding script)
hostFile = 'italy_background.jpg';
wmFile = 'watermarked_hybrid.png'; % change to attacked image if needed
logoFile = 'batman.png';
wavelet = 'haar';
alphaInv = 0.02; % must match embedding strength
%% -----------------------------------------
%% STEP 1 — READ IMAGES
%% -----------------------------------------
hostRGB = im2double(imread(hostFile));
wmRGB = im2double(imread(wmFile));
wmLogo = im2double(imread(logoFile)); % renamed from "logo" to avoid conflict!
%% Convert host & watermarked images to YCbCr
hostYCbCr = rgb2ycbcr(hostRGB);
wmYCbCr = rgb2ycbcr(wmRGB);
% Extract Y (luminance) channel where invisible watermark lives
Y_host = hostYCbCr(:,:,1);
Y_wm = wmYCbCr(:,:,1);
%% -----------------------------------------
%% STEP 2 — APPLY DWT TO BOTH IMAGES
%% -----------------------------------------
[LL_host, ~, ~, ~] = dwt2(Y_host, wavelet);
[LL_wm, ~, ~, ~] = dwt2(Y_wm, wavelet);
%% -----------------------------------------
%% STEP 3 — RECOVER INVISIBLE WATERMARK
%% -----------------------------------------
Wrec = (LL_wm - LL_host) / alphaInv;
Wrec = mat2gray(Wrec); % normalize for visibility
%% Display extracted watermark
figure('Name','Recovered Invisible Watermark','Position',[300 200 500 400]);
imshow(Wrec, []);
title('Recovered Invisible Watermark (LL band difference)');
%% -----------------------------------------
%% STEP 4 — VALIDITY / ACCURACY METRICS
%% -----------------------------------------
% Construct original invisible watermark
origW_raw = rgb2gray(wmLogo);
origW = imresize(origW_raw > 0.5, size(Wrec));
origW = im2double(origW);
% --- MSE ---
mse_val = immse(Wrec, origW);
% --- PSNR ---
psnr_val = psnr(Wrec, origW);
% --- NCC (Normalized Cross Correlation) ---
num = sum(sum(Wrec .* origW));
den = sqrt(sum(sum(Wrec.^2))) * sqrt(sum(sum(origW.^2)));
ncc_val = num / den;
%% Print validity results
fprintf('\n================ WATERMARK VALIDITY METRICS ================\n');
fprintf('MSE = %.6f (lower is better)\n', mse_val);
fprintf('PSNR = %.2f dB (higher is better)\n', psnr_val);
fprintf('NCC = %.4f (1.0 = perfect match)\n', ncc_val);
fprintf('============================================================\n\n');