1. 程式人生 > >二值信息隱藏(分塊和遊程編碼實現)

二值信息隱藏(分塊和遊程編碼實現)

cfa pen play res 上一個 hose 開始 info roc

使用分塊進行信息隱藏,因為在對角線上的分塊上進行的隱藏,所以

可以明顯看到在對角線上有一條線,

200*200的二值圖像

技術分享圖片

512*512的二值圖像

技術分享圖片

技術分享圖片

(二)使用遊程編碼,書上的代碼邏輯上有錯誤,還有一些函數錯誤,根本不能運行出結果

自己修改了得到以下結果

技術分享圖片

200*200的隱藏160位,可以看到微小的變化

技術分享圖片

512*512的隱藏160位,基本看不到變化

技術分享圖片

二值對角線分塊隱藏代碼

技術分享圖片
clc;
clear;

msgfid = fopen(‘hidden.txt‘,‘r‘); % 隱藏信息
[msg, count] = fread(msgfid);
fclose(msgfid);

msg = dec2bin(msg,8);   %將讀入的每個字節轉換成二進制
msg = str2num(msg(:));
watermarklen = count*8;    % 需要隱藏的數目

[fn,pn] = uigetfile({‘*.bmp‘,‘bmpfile(*.bmp)‘;},‘chose file‘);  
filename = strcat(pn,fn);
I = imread(filename);  % 將載體分成 count*count 個小塊,在對角線隱藏信息
[row,col] =size(I);

block(1) = floor(row/watermarklen);  % block的row
block(2) = floor(col/watermarklen);  % block的col
pixelcount = block(1)*block(2); % 一塊的像素數

% 閾值,1的個數必須大於等於此值才能說明隱藏的是1
% 0 的個數必須大於等於此值才能說明隱藏的是 0
if mod(pixelcount, 2) == 0 
    threshold = pixelcount/2 + 1;
else
    threshold = ceil(pixelcount/2);
end
    
carrier = I;  % 修改的操作都在carrier上

zeroCount = zeros(1,watermarklen) ;    % 用來記錄每小塊上0的個數
oneCount = zeros(1,watermarklen);    % 用來記錄每小塊上1的個數

% 統計對角線上的小塊的0和1
for n=1:watermarklen
    %使用求和來算出每個小塊有多少個·1
    oneCount(1,n) = sum(sum(I(block(1)*(n-1)+1:block(1)*n, block(2)*(n-1)+1:block(2)*n)));
    zeroCount(1,n) = pixelcount - oneCount(1,n);
end
%隱藏信息
for n=1:watermarklen
    
    if msg(n,1) == 1; % 嵌入1
        
        if oneCount(1,n) < threshold; % 但是1小於閾值
            modifycount = threshold - oneCount(1,n);  % 需要修改的數目
            k =1;
            for i =block(1)*(n-1)+1:block(1)*n
                for j =block(2)*(n-1)+1:block(2)*n
                    if(carrier(i,j) == 0 && k<=modifycount)
                        carrier(i,j) = 1;
                        k = k+1;
                    end
                end
            end
        end
    else % 嵌入0
        if zeroCount(1,n) < threshold;  % 0的個數小於閾值時需要改
            modifycount = threshold - zeroCount(1,n);
            k =1;
            for i =block(1)*(n-1)+1:block(1)*n
                for j =block(2)*(n-1)+1:block(2)*n
                     if(carrier(i,j) ==1 && k<=modifycount)
                        carrier(i,j) = 0;
                        k = k+1;
                     end
                end
            end
        end
    end
end

%顯示結果
imwrite(carrier,‘bwmarked.bmp‘);  
figure;
imshow(filename);
title(‘原圖‘);
figure;
imshow(‘bwmarked.bmp‘);
title(‘載體‘);
View Code

提取代碼

技術分享圖片
clc;
clear;

[fn,pn] = uigetfile({‘*.bmp‘,‘bmpfile(*.bmp)‘;},‘chose file‘);  
filename = strcat(pn,fn);
I = imread(filename);  % 將載體分成 count*count 個小塊,在對角線隱藏信息
watermarklen = 160;  % 隱藏的數目
[row,col] =size(I);

block(1) = floor(row/watermarklen);  % block的row
block(2) = floor(col/watermarklen);  % block的col
pixelcount = block(1)*block(2); % 一塊的像素數

% 閾值,1的個數必須大於等於此值才能說明隱藏的是1
% 0 的個數必須大於等於此值才能說明隱藏的是 0
if mod(pixelcount, 2) == 0 
    threshold = pixelcount/2 + 1;
else
    threshold = ceil(pixelcount/2);
end

%提取出的隱藏信息
hideInfo = zeros(1,watermarklen);

for n=1:watermarklen
    
    %使用求和來算出每個小塊有多少個·1
    oneCount = sum(sum(I(block(1)*(n-1)+1:block(1)*n, block(2)*(n-1)+1:block(2)*n)));
    if oneCount >= threshold % 1的數目大於閾值,則隱藏的信息為1
        hideInfo(1, n) = 1;
    else                      % 0的數目大於閾值,則隱藏的信息為0
        hideInfo(1, n) = 0;
    end
end


hideInfo = reshape(hideInfo,length(hideInfo)/8,8);  %將二進制字符串分成n行,8列
bin = num2str(hideInfo); % 二進制數值轉變成二進制字符串
dec = bin2dec(bin);%二進制字符串轉換成十進制數組
recoverdata = native2unicode(dec);% 本機編碼轉換成unicode
fprintf(1, ‘恢復出的信息: %s\n‘,recoverdata);
View Code

遊程編碼隱藏代碼

技術分享圖片
clc;
clear;

threshold = 10;
[fn,pn] = uigetfile({‘*.bmp‘,‘bmpfile(*.bmp)‘;},‘chose file‘);  
filename = strcat(pn,fn);
oi = imread(filename);
si = size(oi); % 保存讀入圖像的行列,以便恢復圖像
oi = oi(:);  % 變成一列, 按列變
[len, col] = size(oi); %len= row,1
carrier = oi;   % 以後數據的修改都在carrier上

j=1;
i=1;
%統計遊程長度
while(i <= len)
    last = oi(i); % 依次取出每個數
    count = 1;
    while( i+1 <= len && oi(i+1)== last) % 下一個與上一個相同
        i = i + 1;
        count = count + 1;
    end
    RLE(j) = count;
    j = j + 1;
    i = i + 1;
end

msgfid = fopen(‘hidden.txt‘, ‘r‘);
[msg, msgcount] = fread(msgfid);
fclose(msgfid);

msg = dec2bin(msg,8);   %將讀入的每個字節轉換成二進制
msg = str2num(msg(:));  % 
msgcount = msgcount*8;    % 需要隱藏的數目

i = 1; % msg 的索引
count = 1; % RLE的索引,只為奇數 1 3 5...
sum = 0;
while count < length(RLE)-1
    addSum = RLE(count) + RLE(count+1);   %相鄰兩個數相加的和,從1開始
    
    if count >= 3  
        sum = sum + RLE(count - 1) + RLE(count - 2); % 當前count的在數組中的下標-1
    end
    
    if(addSum >= threshold)  % 只有當相鄰遊程和大於給定數的時候,才隱藏信息
        
        if RLE(count) >= RLE(count+1)
            modifyPoint = sum + RLE(count); % 修改兩個遊程的臨界值,長的那邊的
        else
            modifyPoint = sum + RLE(count) + 1;
        end
        
        if(msg(i) == 0)  % 嵌入的信息為0,但是遊程為奇數,需要修改
            if(mod(RLE(count), 2) == 1) %RLE(count) == ‘奇數‘   
                carrier(modifyPoint) = mod(carrier(modifyPoint)+1 ,2); % 修改點的值取反 mod(carrier(modifyPoint)+1 ,2)
            end
        else  % 嵌入的信息為1,但是遊程為偶數,需要修改
            if mod(RLE(count), 2) == 0 %RLE(count) == ‘偶數‘ 
                carrier(modifyPoint) = mod(carrier(modifyPoint) + 1 ,2); % 修改點的值取反 mod(carrier(modifyPoint)+1 ,2)
            end
        end
        
        i = i + 1; % 隱藏一個位後, msg索引加1
    end
    
    count = count + 2; %不管有沒有隱藏信息,count都要增加
    
    if i == msgcount  % 所有的信息都已隱藏就退出循環
        break;
    end
end

if i < msgcount
    error(‘不能隱藏全部信息!‘);
end

imwrite(reshape(carrier, si(1),si(2)), ‘hide.bmp‘);
figure;
subplot(121);
imshow(reshape(oi, si(1),si(2)));
title(‘原圖‘);
subplot(122);
imshow(‘hide.bmp‘);
title(‘載體‘);
    
View Code

提取代碼

技術分享圖片
clc;
clear;


%也可以增大隱藏信息的間隔 count 1 5 9 13 以後實現
threshold = 3;
[fn,pn] = uigetfile({‘*.bmp‘,‘bmpfile(*.bmp)‘;},‘chose file‘);  
filename = strcat(pn,fn);
oi = imread(filename);
oi = oi(:);  % 變成一列, 按列變
[len, col] = size(oi); %len= row,1

j=1;
i=1;
%統計遊程長度
while(i <= len)
    last = oi(i); % 依次取出每個數
    count = 1;
    while( i+1 <= len && oi(i+1)== last) % 下一個與上一個相同
        i = i + 1;
        count = count + 1;
    end
    RLE(j) = count;
    j = j + 1;
    i = i + 1;
end

i = 1; 
msgcount = 160;
msg = zeros(msgcount,1);
count = 1; % RLE的索引,只為奇數 1 3 5...
while i <= msgcount
   
    addSum = RLE(count) + RLE(count+1);   %相鄰兩個數相加的和,從1開始   
    if(addSum >= threshold)  % 只有當相鄰遊程和大於給定數的時候,才隱藏信息
        if mod(RLE(count),2) == 0
            msg(i) = 0;
        else
            msg(i) = 1;
        end
        i = i + 1;
    end
    count = count + 2;     
end

hideInfo = reshape(msg,length(msg)/8,8);  %將二進制字符串分成n行,8列
bin = num2str(hideInfo); % 二進制數值轉變成二進制字符串
dec = bin2dec(bin);%二進制字符串轉換成十進制數組
recoverdata = native2unicode(dec);% 本機編碼轉換成unicode
fprintf(1, ‘恢復出的信息: %s\n‘,recoverdata);
View Code

二值信息隱藏(分塊和遊程編碼實現)