美文网首页
基于matlab和python的LSB隐写实现

基于matlab和python的LSB隐写实现

作者: 奈何缘浅wyj | 来源:发表于2021-04-06 10:10 被阅读0次

    将字符串嵌入图片可以顺序选取像素点,也可以随机选取像素点。下面我们依次来实现每种算法。

    1. 顺序嵌入

    顺序嵌入很简单,遍历每个像素点,然后将二进制嵌入最后一位即第八位即可。

    为了写报告,我还画了一个流程图,这里贴上来方便理解:

    1.1 python版本

    首先我用python实现了一个,主要是对matlab不熟悉,利用python3的PIL库写起来还是很简单的。直接看代码吧

    # coding:utf-8
    # python 3.6.6
    
    from PIL import Image
    import time
    
    # 将字符串转为二进制
    def str_convert_bin(s):
        result = ''
        for c in s:
            b = bin(ord(c)).replace('0b', '')
            b = '0'*(7-len(b))+b
            result = result+b
        return result
    
    # 将二进制转化为字符串
    def bin_convert_str(b):
        str=''
        # 将二进制字符串每7位分割,成列表
        b1 = [b[i:i+7] for i in range(0, len(b), 7)]
        for i in range(len(b1)):
            b2 = chr(int(b1[i],2))
            str = str+b2
        return str
    
    # 将二进制字符串嵌入图片像素B通道 im:Image()、bin1:要嵌入的二进制串
    def insert(im,bin1):
        size = im.size
        length = len(bin1)
        k=0
        flag=0
        for i in range(size[0]):
            for j in range(size[1]):
                # im.getpixel((i,j))读取像素点(i,j)的像素值
                pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
                if pixel_b[-1:]<bin1[k]:
                    # im.putpixel((i,j),(x,y,z))设置像素点(i,j)的RGB值为(x,y,z)
                    im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]+1))
                if pixel_b[-1:]>bin1[k]:
                    im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]-1))    
                k=k+1 
                if k==length:
                    flag=1
                    break
            if flag==1:
                break
        print("字符串嵌入完成\n\n")
    
    # 提取字符串 im:Image()、length:二进制字符串长度
    def extract(im,length):
        size = im.size
        k=0
        result=''
        flag=0
        for i in range(size[0]):
            for j in range(size[1]):
                pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
                result=result+pixel_b[-1:]
                k=k+1 
                if k==length:
                    flag=1
                    break
            if flag==1:
                break
        print("提取完成,二进制字符串为:\n%s"%result)
        str = bin_convert_str(result)
        print("转换完成,结果为:\n%s"%str)
    
    def main():
        test_str=input("请输入字符串:\n")
        result = str_convert_bin(test_str)
        print("待嵌入字符串转化为二进制为:\n%s"%result)
        print("开始嵌入....")
        im = Image.open("2.bmp")
        insert(im, result)
    
        time.sleep(5)
        print("开始提取字符串:")
        extract(im, len(result))
    
    if __name__=='__main__':
        main()
    

    结果:

    1.2 matlab 版本

    后续更复杂的隐写还是需要用到matlab,于是乎还是转matlab吧。

    matlab就不介绍了,我也是先学先用,代码写得粗糙,勉强贴上代码:

    % By gengyanqing
    % LSB隐藏(顺序隐藏)
    % 可以隐藏数字、字母、英文字符 ex: hello,world.111
    % jpg失真!用png/bmp
    
    clear all;clc;
    data=imread('1.png');  % 读入图片
    str=input('请输入要潜入的字符串:','s'); % 接收字符串
    str_bin_mat=dec2bin(str); % 字符串转二进制矩阵
    
    % 二进制矩阵转字符串
    l_str_bin_mat=size(str_bin_mat); %二进制矩阵
    str_bin='';
    for i=1:l_str_bin_mat(1)
        for j=1:l_str_bin_mat(2)
            str_bin=[str_bin,str_bin_mat(i,j)];
        end
    end
    disp('待嵌入的字符串二进制形式为');
    disp(str_bin);
    
    % 检测是否能够完全嵌入
    [l,w,h]=size(data);
    if length(str_bin)>=l*w*h
        error('字符长度超出!!!');
    end
    
    %嵌入程序
    data1=data;
    disp('开始嵌入');
    flag1=1; %输入字符二进制长度,判断嵌入是否结束
    flag2=1;
    flag3=1;
    for i=1:l
        if flag3==0
            break
        end
        for j=1:w
            if flag2==0
                flag3=0;
                break
            end
            for k=1:h
                if flag1>length(str_bin)
                    disp('over');
                    flag2=0;
                    break
                end
                a=dec2bin(data1(i,j,k),8);%数字取二进制
                data1(i,j,k)=bin2dec([a(1:7),str_bin(flag1)]);%二进制相加,再取十进制  
                flag1=flag1+1;
            end
        end
    end
    %保存图片
    imwrite(data1,'1-2.png')
    disp('嵌入完成,保存为1-2.png');
    
    %以下为提取程序
    disp('开始提取...')
    data2 = imread('1-2.png');
    [l,w,h]=size(data2);
    str_bin1='';%提取到的二进制字符串
    locationx=[];
    locationy=[];
    locationxy=[];
    m=length(str_bin);
    flag1=1;
    flag2=1;
    flag3=1;
    for i=1:l
        if flag3==0
            break
        end
        for j=1:w
            if flag2==0
                flag3=0;
                break
            end
            for k=1:h
                if flag1>length(str_bin)
                    flag2=0;
                    break
                end
                a=dec2bin(data2(i,j,k),8);%十进制转二进制
                str_bin1=[str_bin1,a(8)];% 取最后一个数
                flag1=flag1+1;
            end
        end
    end
    disp('提取完成!');
    disp('提取到的二进制字符串为:');
    disp(str_bin1);
    disp('开始转换...')
    
    % 二进制转字符串
    str2='';
    for q=1:length(str_bin1)/l_str_bin_mat(2)
        w=str_bin1((q-1)*l_str_bin_mat(2)+1:q*l_str_bin_mat(2));%w为每七位
        a=bin2dec(w); % 转换为十进制
        if a>9
            str2=[str2,char(a)];
        end
        if a<9
            str2=[str2,a];
        end
    end
    disp('转换完成');
    disp('最终结果为:');
    disp(str2);
    

    可以嵌字符,数字,字母,结果如下:

    2. 随机LSB隐写

    其实这个和顺序差不多,无非就是在遍历像素点的时候,将(i,j)改为随机的点,我们可以写个随机函数随机生成列表X和Y,当要嵌入(i,j)时我们就将其变为(X(i+j), Y(i+j)),为什么不是(X(i), Y(j))读者可以想想(这样不随机)。

    这个我也画了一个流程图,但是好像有问题,时间紧急就暂且这样吧。

    接下来看生成随机列表的函数 randomxy.m:

    % 随机生成两个列表
    % l为长,w为宽,len_str_bin为嵌入二进制长度,key为随机种子
    function [x,y]=randxy(l,w,len_str_bin,key)
        %设置随机种子,生成一串随机数
        rand('seed',key);
        disp('hhhhhhhhh');
        x=randperm(l,len_str_bin);
        y=randperm(w,len_str_bin);
        %x = unique(x); %去重处理
        %y = unique(y) ;%去重处理
    end
    

    然后看主要代码:

    % By gengyanqing
    % LSB隐藏(随机隐藏)
    % 可以隐藏数字、字母、英文字符 ex: hello,world.111
    % jpg失真!用png/bmp
    
    clear all;clc;
    data=imread('1.png');  % 读入图片
    str=input('请输入要潜入的字符串:','s'); % 接收字符串
    str_bin_mat=dec2bin(str); % 字符串转二进制矩阵
    
    % 二进制矩阵转字符串
    l_str_bin_mat=size(str_bin_mat); %二进制矩阵
    str_bin='';
    for i=1:l_str_bin_mat(1)
        for j=1:l_str_bin_mat(2)
            str_bin=[str_bin,str_bin_mat(i,j)];
        end
    end
    disp('待嵌入的字符串二进制形式为');
    disp(str_bin);
    
    % 检测是否能够完全嵌入
    [l,w,h]=size(data);
    if length(str_bin)>=l*w*h
        error('字符长度超出!!!');
    end
    
    %嵌入程序
    data1=data;
    disp('开始嵌入');
    flag1=1; %输入字符二进制长度,判断嵌入是否结束
    flag2=1;
    flag3=1;
    % 调用randxy函数
    [x,y]=randxy(l,w,length(str_bin),88);
    for i=1:l
        if flag3==0
            break
        end
        for j=1:w
            if flag2==0
                flag3=0;
                break
            end
            for k=1:h
                if flag1>length(str_bin)
                    disp('over');
                    flag2=0;
                    break
                end
                a=dec2bin(data1(x(i+j),y(i+j),k),8);%数字取二进制
                data1(x(i+j),y(i+j),k)=bin2dec([a(1:7),str_bin(flag1)]);%二进制相加,再取十进制  
                flag1=flag1+1;
            end
        end
    end
    %保存图片
    imwrite(data1,'1-2.png')
    disp('嵌入完成,保存为1-2.png');
    
    %以下为提取程序
    %这里提供了x和y,提取二进制字符串位数的信息
    disp('开始提取...')
    data2 = imread('1-2.png');
    [l,w,h]=size(data2);
    str_bin1='';%提取到的二进制字符串
    locationx=[];
    locationy=[];
    locationxy=[];
    m=length(str_bin);
    flag1=1;
    flag2=1;
    flag3=1;
    for i=1:l
        if flag3==0
            break
        end
        for j=1:w
            if flag2==0
                flag3=0;
                break
            end
            for k=1:h
                if flag1>length(str_bin)
                    flag2=0;
                    break
                end
                a=dec2bin(data2(x(i+j),y(i+j),k),8);%十进制转二进制
                locationx=[locationx,x(i+j)];%随机点x坐标
                locationy=[locationy,y(i+j)];%随机点y坐标
                locationxy=[locationxy;x(i+j),y(i+j),k];
                str_bin1=[str_bin1,a(8)];% 取最后一个数
                flag1=flag1+1;
            end
        end
    end
    disp('提取完成!');
    disp('提取到的二进制字符串为:');
    disp(str_bin1);
    disp('开始转换...')
    
    % 二进制转字符串
    str2='';
    for q=1:length(str_bin1)/l_str_bin_mat(2)
        w=str_bin1((q-1)*l_str_bin_mat(2)+1:q*l_str_bin_mat(2));%w为每七位
        a=bin2dec(w); % 转换为十进制
        if a>9
            str2=[str2,char(a)];
        end
        if a<9
            str2=[str2,a];
        end
    end
    disp('转换完成');
    disp('最终结果为:');
    disp(str2);
    
    disp('随机位置分别为');
    disp(locationxy);
    plot(locationx,locationy);
    

    结果:

    下图为隐藏点的图(可以看出来确实是随机的)

    相关文章

      网友评论

          本文标题:基于matlab和python的LSB隐写实现

          本文链接:https://www.haomeiwen.com/subject/eulskltx.html