Matlab彩色图像隐写算法问题:提取图像与原秘密图像不符
彩色图像隐写算法提取异常问题排查与修复
问题背景
我在Matlab中实现了彩色图像隐写算法:将秘密图像的每个像素(8位)拆分为4组2位数据,分别替换载体图像中对应4个像素的最低2位。但提取出的图像与原秘密图像不一致,效果异常。
原代码
clear; clc; cover = imread('colored.jpg'); secret = imread('c4.png'); row = size(secret,1); col = size(secret,2); col = col -mod(col, 4); if size(cover, 1) < row*4 || size(cover, 2) < col*4 error('Cover image is too small to hide the hidden image.'); end disp(size(secret)); for i=1:row for j=1:4:col for k=1:3 sbyte = secret(i,j,k); sbyte = dec2bin(sbyte, 8); start=1; for l=j:j+3 cbyte = cover(i,l,k); cbyte = dec2bin(cbyte, 8); seg = sbyte(start:start+1); cbyte(end-1:end) = seg; cbyte = bin2dec(cbyte); cover(i,l,k) = cbyte; start = start+2; end end end end imwrite(cover, 'stego_image.png'); disp('----------'); hidden = zeros(size(secret)); stego = imread('stego_image.png'); for i=1:row for j=1:4:col for k=1:3 sbyte = ''; for l=j:j+3 cbyte = stego(i,l,k); cbyte = dec2bin(cbyte, 8); sbyte = strcat(sbyte, cbyte(end-1:end)); end hidden(i,j,k) = bin2dec(sbyte); end end end disp(size(hidden)); hidden = uint8(hidden) .* secret; imshow(hidden);
错误分析
- 尺寸不匹配:对秘密图像列数做了
col = col - mod(col,4)截断,但后续创建hidden数组仍使用原秘密图像尺寸,提取时仅处理了前col列(截断后的列数),剩余列像素为0,导致图像错位、缺失。 - 载体索引逻辑错误:原代码中用
j:j+3作为载体像素的列索引,当j步长为4时,会重复覆盖载体图像的列,导致秘密信息写入位置混乱。 - 提取赋值范围错误:提取循环中仅给
hidden(i,j,k)赋值,但秘密图像中j+1、j+2、j+3列的像素未被处理,这些位置始终为0。 - 多余的像素相乘:最后一行
hidden = uint8(hidden) .* secret完全没必要,会把提取出的像素与原秘密图像像素相乘,破坏正确提取的内容。
修正后的代码
clear; clc; % ---------------------- 嵌入阶段 ---------------------- cover = imread('colored.jpg'); secret = imread('c4.png'); row_secret = size(secret, 1); col_secret = size(secret, 2); % 对秘密图像列数做4的倍数截断,确保每个秘密像素对应4个载体像素 col_secret_trim = col_secret - mod(col_secret, 4); secret_trim = secret(:, 1:col_secret_trim, :); % 检查载体图像尺寸:每个秘密像素需要对应载体的4个连续列 if size(cover, 1) < row_secret || size(cover, 2) < col_secret_trim * 4 error('载体图像尺寸过小,无法隐藏秘密图像'); end disp('裁剪后的秘密图像尺寸:'); disp(size(secret_trim)); % 嵌入秘密信息 for i = 1:row_secret % 遍历每个秘密像素的列 for j = 1:col_secret_trim for k = 1:3 % 处理RGB三个通道 s_val = secret_trim(i, j, k); s_bin = dec2bin(s_val, 8); % 转为8位二进制字符串 % 载体图像对应的4个连续列 carrier_cols = (j-1)*4 + 1 : j*4; start_idx = 1; for l = carrier_cols c_val = cover(i, l, k); c_bin = dec2bin(c_val, 8); % 用秘密二进制的2位替换载体最低2位 c_bin(end-1:end) = s_bin(start_idx:start_idx+1); cover(i, l, k) = bin2dec(c_bin); start_idx = start_idx + 2; end end end end imwrite(cover, 'stego_image.png'); disp('隐写图像已保存'); % ---------------------- 提取阶段 ---------------------- stego = imread('stego_image.png'); % 提前指定uint8类型,避免类型转换错误 hidden = zeros(row_secret, col_secret_trim, 3, 'uint8'); for i = 1:row_secret for j = 1:col_secret_trim for k = 1:3 s_bin = ''; carrier_cols = (j-1)*4 + 1 : j*4; for l = carrier_cols c_val = stego(i, l, k); c_bin = dec2bin(c_val, 8); s_bin = strcat(s_bin, c_bin(end-1:end)); end hidden(i, j, k) = bin2dec(s_bin); end end end disp('提取出的秘密图像尺寸:'); disp(size(hidden)); imshow(hidden); imwrite(hidden, 'extracted_secret.png'); disp('提取出的秘密图像已保存');
修正说明
- 对秘密图像做了实际裁剪,确保后续处理的尺寸一致,避免错位。
- 修正了载体像素的索引逻辑:每个秘密像素对应载体图像中连续4列(从
(j-1)*4+1到j*4),解决了原代码中索引混乱的问题。 - 去掉了多余的
hidden = uint8(hidden) .* secret,直接显示提取结果。 - 提前将
hidden数组设为uint8类型,避免类型转换导致的像素值异常。
内容的提问来源于stack exchange,提问作者hassan Al-khafagy
相关产品推荐
相关产品推荐

