【问题标题】:Read RGB image into binary and display it as RGB in Matlab将RGB图像读入二进制并在Matlab中显示为RGB
【发布时间】:2018-04-17 14:16:17
【问题描述】:

这个问题是基于之前提出的Understanding image steganography by LSB substitution method

为了使代码高效并减少均方误差 (MSE),建议是:“按原样读取文件并将其转换为带有 de2bi(fread(fopen(filename)), 8) 的位。将这些位以最小需要 k 因子,可能是 1 或 2。当您提取秘密时,您将能够重建原始文件。这是我一直在尝试的,但在某处我做错了,因为我没有得到任何显示。但是,MSE确实降低了。基本上,我对如何将图像转换为二进制、对该数据执行算法并在提取后显示图像感到困惑。

有人可以帮忙吗?

【问题讨论】:

  • 您询问如何使用 RGB 或灰度图像来执行此操作。澄清一下,您指的是这里的封面图片吗?
  • 恐龙图像的长度为 594138 字节,或乘以 8 位。你的封面图片有 512 * 512 * 3 像素。您的封面中有 6.05 个与像素一样多的秘密 bts,这意味着您必须嵌入 7 个最高有效位才能适应整个消息。换句话说,这是一个太大的文件。如果您将密钥的大小调整为 256x256,它的文件大小会小得多并且更易于管理。
  • @Reti43:两个图像的大小和 RGB 相同。将 RGB 秘密图像(dino 文件)嵌入到任何一个通道的 7 个最高有效位平面或 8 个最高有效位平面中的 RGB 封面图像中对我来说是可以的。一旦我了解您的建议是什么以及如何实施它,我以后可以在此基础上再接再厉。我想我按照您建议的方式将图像转换为二进制,它确实提供了较低的 MSE。但接下来的问题是将这些二进制文件转换为图像以便显示。这我不明白该怎么做。当您更好地了解情况时,您能否再次提供帮助。谢谢
  • @Reti43:根据您的建议,我使用imread 读取图像,然后转换为二进制de2bi。 LSB 应用于此二值图像。但正如您从更新的问题中看到的那样,我无法显示提取的图像。 MSE 已减少,但我无法显示提取的图像。
  • 删除问题中的代码会适得其反,因为这对于理解您的问题至关重要,并且无论如何都可以通过修订历史访问。

标签: algorithm matlab image-processing fread steganography


【解决方案1】:

我已经对您的代码进行了一些修改,以使其能够正常工作,而不管实际图像是什么。但是,它们都需要是彩色或灰度的。还有一些错误,您的代码不允许我在我的 MATLAB 版本上运行它。

首先,您没有正确阅读图像。您正在为图像打开一个字节流,然后在字节流上使用imread 来读取图像。这是错误的 - 只需提供实际文件的路径即可。

其次,图像已经在uint8 中,因此您可以在此本地执行位的置换和移位。

您的代码的其余部分与以前相同,除了图像大小调整。您无需指定通道数。此外,bitcmp 存在语法错误。我使用 'uint8' 而不是值 8 因为我的 MATLAB 版本要求您指定预期数据类型的字符串。 8 这里的值我假设你的意思是 8 位,所以把 'uint8' 放在这里是有意义的。

我还将直接从 Stack Overflow 读取您的图片。我假设恐龙图像是封面,而花朵是信息:

%%% Change
x = imread('https://i.stack.imgur.com/iod2d.png');         % cover message
y  = imread('https://i.stack.imgur.com/Sg5mr.png');    % message image
n = input('Enter the no of LSB bits to be subsituted- ');

                                     %%% Change
S = uint8(bitor(bitand(x,bitcmp(2^n-1,'uint8')),bitshift(y,n-8))); %Stego
E = uint8(bitand(255,bitshift(S,8-n))); %Extracted

origImg = double(y);   %message image
distImg = double(E);   %extracted image

[M N d] = size(origImg);
distImg1=imresize(distImg,[M N]); % Change

figure(1),imshow(x);title('1.Cover image')
figure(2),imshow(y);title('2.Message to be hide')
figure(3),imshow((abs(S)),[]);title('3.Stegnographic image')
figure(4),imshow(real(E),[]); title('4.Extracted image');

这为我运行,我设法重建消息图像。将位数选择为 4 左右可以让您在封面和消息图像之间取得良好的折衷。

【讨论】:

  • 感谢您的回复。但是有几个问题。 (1)根据我上一个问题的答案,我应该改进代码以获得更好的图像提取。为此,建议将图像转换为二进制,并在二进制图像上进行操作。这减少了均方误差。但是,我无法显示图像,因为可能我没有使用正确的操作来读取和显示从十进制到二进制的图像。这就是我发布这个问题的原因,因为在将图像转换为二进制后,我无法使用imshow() 显示。
  • 建议是:“按原样读取文件并使用 de2bi(fread(fopen(filename)), 8) 将其转换为位。将这些位以最小 k 因子嵌入您的封面图像需要,可能是 1 或 2。当您提取秘密时,您将能够重建原始文件。这是我一直在尝试但无法做到的。您能否提供有关如何将算法应用于图像的二进制版本的代码?当前版本的代码对位平面 1-4 给出了非常高的均方误差。 (2) 此外,提取的图像在当前版本中亮度较差。
  • 在图片上方使用im2bw。这会将图像转换为二进制。
  • 抱歉,我无法理解您指的是哪一行。如果原始图像-封面和秘密并转换为二进制,我将如何显示提取的图像?
  • @RiaGeorge 我对您的域了解不够。对不起。我会删除我的答案。
【解决方案2】:

加载字节流而不是秘密的像素数组将导致更小的有效负载。它会变得多小取决于图像格式和颜色的重复程度。

imread() 需要一个文件名并加载一个像素数组,如果该文件名是一个有效的图像文件。加载文件的字节流并将其传递给imread() 是没有意义的。你要的是这个

% read in the byte stream of a file
fileID = fopen(filename);
secretBytes = fread(fileID);
fclose(fileID);

% write it back to a file
fileID = fopen(filename);
fwrite(fileID, secretBytes);
fclose(fileID);

请注意,封面图像是作为像素数组加载的,因为您需要对其进行修改。

您的有效载荷大小为length(secretBytes) * 8,它必须适合您的封面图片。如果您决定为所有颜色平面嵌入k 每像素位,则必须满足以下要求

secretBytes * 8 <= prod(size(coverImage)) * k

如果您只想嵌入一个颜色平面,无论您的覆盖介质是RGB还是灰度,您都需要将其修改为

secretBytes * 8 <= size(coverImage,1) * size(coverImage,2) * k

如果不满足此要求,您可以选择

  • 停止进程
  • 要求用户嵌入更小的文件
  • 增加k
  • 包括更多颜色平面(如果有)

以下是仅在最低有效位 (k = 1) 中嵌入一个颜色平面的原型。

HEADER_LEN = 24;

coverImage = imread('lena.png');
secretBytes = uint8('Hello world'); % this could be any byte stream

%% EMBEDDING
coverPlane = coverImage(:,:,1);     % this assumes an RGB image
bits = de2bi(secretBytes,8)';
bits = [de2bi(numel(bits), HEADER_LEN) bits(:)'];
nBits = length(bits);
coverPlane(1:nBits) = bitset(coverPlane(1:nBits),1,bits);
coverImage(:,:,1) = coverPlane;

%% EXTRACTION
nBits = bi2de(bitget(coverPlane(1:HEADER_LEN),1));
extBits = bitget(coverPlane(HEADER_LEN+1:HEADER_LEN+nBits),1);
extractedBytes = bi2de(reshape(extBits',8,length(extBits)/8)')';

除了您的消息字节,您还必须嵌入密钥的长度,以便提取器知道要提取多少位。

如果您嵌入 k > 1 或多个颜色平面,逻辑会变得更加复杂,您必须小心如何实现更改。

例如,您可以选择一次嵌入每个颜色平面,直到用完要隐藏的位,或者您可以使用 coverImage(:) 展平整个像素阵列,这将嵌入每个像素的 RGB,一次一个像素,直到用完比特。

如果嵌入 k > 1,则必须用 0 填充 bits 向量,直到其长度可被 k 整除。然后你可以将你的位组合成 k 组与

bits = bi2de(reshape(a',k,length(bits)/k)')';

要嵌入它们,您需要重新使用 bitand()bitor()

coverPlane(1:nBits) = bitor(bitand(coverPlane(1:nBits), bitcmp(2^k-1,'uint8')), bits);

还有更多细节,例如准确提取 24 位的消息长度,我不能强调您必须非常仔细地考虑如何实现所有这些内容。您不能只从不同的代码 sn-ps 拼接部分并期望一切都按照您的意愿去做。

【讨论】:

  • 再次感谢您的帮助。我已尽力整理答案,但我不断收到错误消息。我已将代码放在问题的更新部分。那么如何显示提取的文件呢?我应该把它转换成uint8吗?你能看看吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 2015-11-18
  • 2015-03-14
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 2011-09-15
相关资源
最近更新 更多