clc;
clear;
close all;
alpha = 0.05; % 水印嵌入强度
level = 2; % DWT分解层级
origPath = 'zlh.jpg'; % 原始图像
wmPath = 'shuiyin.png'; % 水印图像
% 读取并预处理原始图像(转为灰度图)
I = imread(origPath);
if size(I, 3) == 3
I = rgb2gray(I);
end
I = im2double(I); % 转换为双精度浮点类型
% 读取并预处理水印图像(转为灰度图+二值化)
wm = imread(wmPath);
if size(wm, 3) == 3
wm = rgb2gray(wm);
end
wm = imbinarize(im2double(wm)); % 转换为双精度并二值化
% 调整水印尺寸(使用小波分解后最低层水平细节系数尺寸)
origSize = size(I);
cHSize = floor(origSize ./ (2^level)); % 计算各层分解后的尺寸
wm = imresize(wm, cHSize(1:2)); % 调整水印尺寸
wm = imbinarize(wm); % 确保二值化
% 显示原始图像和水印
figure;
subplot(1, 2, 1); imshow(I); title('原始图像');
subplot(1, 2, 2); imshow(wm); title('水印图像');
% 执行水印嵌入
watermarkedImg = embedWatermark(I, wm, alpha, level);
% 执行水印提取(无需原始图像,修正后改为仅需含水印图像)
extractedWm = extractWatermark(watermarkedImg, alpha, level);
% 显示结果
figure;
subplot(1, 3, 1); imshow(I); title('原始图像');
subplot(1, 3, 2); imshow(watermarkedImg); title('含水印图像');
subplot(1, 3, 3); imshow(extractedWm); title('提取的水印');
% 评估指标
% 峰值信噪比(图像范围[0,1])
mse = mean((I(:) - watermarkedImg(:)).^2);
psnr = 10*log10(1 / mse);
% 水印相似度(归一化互相关NC)
similarity = corr2(wm, extractedWm);
% 误码率BER
ber = sum(wm(:) ~= extractedWm(:)) / numel(wm);
fprintf('=== 水印系统性能评估 ===\n');
fprintf('PSNR: %.2f dB\n', psnr);
fprintf('相似度(NC): %.4f\n', similarity);
fprintf('误码率(BER): %.4f\n', ber);
% 攻击测试
attackTypes = {'gaussian', 'saltpepper', 'crop', 'blur'};
results = cell(length(attackTypes), 4); % 存储攻击结果
figure;
set(gcf, 'Position', [100, 100, 1200, 900]); % 设置大窗口尺寸
for i = 1:length(attackTypes)
% 执行攻击
attackedImg = attackTest(watermarkedImg, attackTypes{i});
% 提取水印(攻击后图像提取)
attackedWm = extractWatermark(attackedImg, alpha, level);
% 计算相似度
sim = corr2(wm, attackedWm);
% 显示结果
subplot(4, 3, (i-1)*3+1);
imshow(attackedImg);
title(['攻击: ' attackTypes{i}]);
subplot(4, 3, (i-1)*3+2);
imshow(attackedWm);
title('提取水印');
subplot(4, 3, (i-1)*3+3);
imshowpair(wm, attackedWm, 'diff');
title(['相似度: ', num2str(sim, '%.4f')]);
% 存储结果
results{i, 1} = attackTypes{i};
results{i, 2} = attackedImg;
results{i, 3} = attackedWm;
results{i, 4} = sim;
end
% 显示结果表格
fprintf('\n鲁棒性测试结果:\n');
fprintf('%-12s %-12s\n', '攻击类型', '相似度');
fprintf('-----------------------\n');
for i = 1:size(results, 1)
fprintf('%-12s %.4f\n', results{i, 1}, results{i, 4});
end
%% 水印嵌入函数(修正重构逻辑和尺寸处理)
function watermarkedImg = embedWatermark(origImg, wmImg, alpha, level)
% 小波分解并存储各层系数
[cA, cH, cV, cD] = dwt2(origImg, 'haar');
coeffs = {cA, cH, cV, cD};
for i = 2:level
[cA, cH, cV, cD] = dwt2(coeffs{1}, 'haar');
coeffs = {cA, cH, cV, cD, coeffs{:}}; % 分层存储系数
end
% 提取最深层水平细节系数
targetCH = coeffs{2}; % 第level层的cH位于第2个元素(分层存储后)
% 调整水印尺寸并二值化(确保与目标系数尺寸一致)
if ~isequal(size(wmImg), size(targetCH))
wmImg = imresize(wmImg, size(targetCH));
wmImg = imbinarize(wmImg);
end
% 嵌入水印到水平细节分量
targetCH_modified = targetCH + alpha * double(wmImg);
% 重构系数(从最深层开始替换并逐层重构)
coeffs{2} = targetCH_modified; % 替换修改后的cH
% 逐层重构(逆序处理)
recon = coeffs{1}; % 最低频分量
for i = 1:level
layer = level - i + 1;
cA_current = recon;
cH_current = coeffs{2 + 3*(i-1)}; % 计算当前层cH位置
cV_current = coeffs{3 + 3*(i-1)};
cD_current = coeffs{4 + 3*(i-1)};
recon = idwt2(cA_current, cH_current, cV_current, cD_current, 'haar');
end
% 裁剪到原始尺寸并转换类型(确保数值范围[0,1])
watermarkedImg = recon(1:size(origImg,1), 1:size(origImg,2));
watermarkedImg = max(min(watermarkedImg, 1), 0); % 防止数值越界
watermarkedImg = im2uint8(watermarkedImg); % 转换为uint8
end
%% 水印提取函数(移除对原始图像的依赖,仅需含水印图像)
function extractedWm = extractWatermark(watermarkedImg, alpha, level)
% 转换为双精度并分解含水印图像
watermarkedImg = im2double(watermarkedImg);
[cA_wm, cH_wm, cV_wm, cD_wm] = dwt2(watermarkedImg, 'haar');
coeffs_wm = {cA_wm, cH_wm, cV_wm, cD_wm};
for i = 2:level
[cA_wm, cH_wm, cV_wm, cD_wm] = dwt2(coeffs_wm{1}, 'haar');
coeffs_wm = {cA_wm, cH_wm, cV_wm, cD_wm, coeffs_wm{:}};
end
% 提取最深层水平细节系数
targetCH_wm = coeffs_wm{2};
% 假设原始图像分解后的最深层cH为全0(简单盲提取,实际需原始分解系数)
% 注:实际鲁棒水印需存储原始图像的分解系数,此处为简化示例
targetCH_orig = zeros(size(targetCH_wm));
extractedWm = (targetCH_wm - targetCH_orig) / alpha;
% 二值化处理(阈值0.5)
extractedWm = imbinarize(extractedWm, 0.5);
end
%% 攻击测试函数(修正变量名和数值范围处理)
function attackedImg = attackTest(img, attackType)
% 确保输入为双精度(0-1范围)
if ~isa(img, 'double')
img = im2double(img);
end
switch attackType
case 'gaussian'
attackedImg = imnoise(img, 'gaussian', 0, 0.01); % 均值0,方差0.01
case 'saltpepper'
attackedImg = imnoise(img, 'salt & pepper', 0.05); % 椒盐噪声密度0.05
case 'crop'
% 裁剪图像左上角50x50像素(改为保留非裁剪区域)
attackedImg = img(51:end, 51:end);
% 若需填充0,需调整尺寸:attackedImg = zeros(size(img)); attackedImg(51:end,51:end) = img(51:end,51:end);
case 'blur'
h = fspecial('gaussian', [5 5], 1); % 5x5高斯模糊核,标准差1
attackedImg = imfilter(img, h, 'replicate'); % 边缘填充避免尺寸变化
otherwise
attackedImg = img;
end
% 确保数值范围[0,1]并转换为uint8
attackedImg = max(min(attackedImg, 1), 0);
attackedImg = im2uint8(attackedImg);
end
哪里有错