• 【小聪明】图片消失在另一张图片里


    概要

     

    偶然看到一篇文章伪·黑科技】基于像素微调实现的文字隐写术,受此启发,能把文字转成二进制,那么图片像素转成二进制岂不更容易,于是我就写了一个隐藏图片的代码,也就有了这篇随笔。

    但是刚写出来不完美,有几点需要改进的地方,现在还没有想通,做此记录,以后有机会再慢慢改进:

    • python 包 matplotlib 保存数组构成的图片时,会自动加个透明层,即不是我想要的 RGB 格式,而是 RGBA 格式。why,why,不得不转向其它包
    • 包存图片格式时,一般的数组有可能格式不对,如果遇到错误,就保存为 unit8 格式

     


    效果图

     

    提示:这是我截的图,不是原图,像素可能不满足要求,做实验可用自己的图片

    图 1:要被隐藏的图片

    图 2:隐藏之后的图片效果图


    代码

     

    基本的原理就是利用二进制微调宿主像素。代码中的解释已经很清楚了,在此不再多述。

    # -*- coding: utf-8 -*-
    """
    Created on Thu Mar 29 11:47:43 2018
    
    @author: zhoukui
    """
    import numpy as np
    from PIL import Image
    import matplotlib.image as mpimg
    
    import sys
    
    def image2Bin(imageFile):
        image = mpimg.imread(imageFile)
        imageArr = image.ravel()
        
        binList = list((map(bin,imageArr)))
        
        for i, item in enumerate(binList):  # 把数字全部转换为 8 位的 0 1 数据 
            binList[i] = item[2:]  # 把二进制标志 '0b' 去掉
            binList[i] = '0'*(8 - len(binList[i])) + binList[i]
        
        pixes_x, pixes_y, _ = image.shape # 把原始图片像素保存一下
        
        binX = bin(pixes_x)[2:]
        binY = bin(pixes_y)[2:]
        binList.insert(0,'0'*(16-len(binX)) + binX)
        binList.insert(1,'0'*(16-len(binY)) + binY)
        # 前两个 16 位表示的是像素长宽,像素长宽相乘再乘以 3 得到后面 8 位的数目
        return binList  
    
    def showImage(imageArr, imageTitle):
        
        im = Image.fromarray(imageArr)
        im.save(imageTitle)
        im.show()
        
    
        
    def oneHide(pix, pixValue):
        if pix == '0':  # 使图片像素变为偶数
             if pixValue == 255:
                  pixValue = 244
             elif pixValue % 2 == 1:
                  pixValue += 1 
        elif pixValue % 2 == 0:
             pixValue += 1
        
        return pixValue  # 返回去改变这像素值     
    
    def hiding(binList, hidingImageFile):
        image = mpimg.imread(hidingImageFile)
        #print(image.shape)
        imageArr = image.ravel()
        
        # 每一个像素隐藏一个 0 或者 1
        # 判断是否藏得下
        if (len(binList)*8+16 > len(imageArr)):
            print("藏不下,换一张宿主更大的图片或把要藏的图片调小")
        else:
            flag = 0  # 标记藏到哪了
            # 先藏前两个 16 位的
            for i in range(2):
                for j in range(16):
                    imageArr[flag] = oneHide(binList[i][j], imageArr[flag])
                    flag += 1
            
            # 然后藏剩下的
            for _, item in enumerate(binList[2:]): 
                if flag % 8640 == 0:
                    sys.stdout.write('
     complete percent ----->:%.0f%%' % (flag/82976.))                
                for j in range(8):
                    imageArr[flag] = oneHide(item[j], imageArr[flag])
                    flag += 1
            
            sys.stdout.flush()  
        #print(imageArr[:8])
        imageArr = imageArr.reshape(image.shape)  #.astype(np.uint8) 
        
        return imageArr      
    
    def imerging(imageFile):
        image = mpimg.imread(imageFile)  # 这种读取图片直接是 Ndarray
        
        imageArr = image.ravel()
        
        # 先把隐藏图片的大小解析出来
        tempList = [str(i % 2) for i in imageArr[:32]] 
        
        pixesX = int(''.join(tempList[:16]), 2)
        pixesY = int(''.join(tempList[16:]), 2)
        #print(pixesX, pixesY)
        
        # 把隐藏图片的像素解析出来
        temp2List = [str(i % 2) for i in imageArr[32 : 32 + pixesX*pixesY*3*8]]
        
        tempArr = np.zeros(pixesX*pixesY*3,)
    
        for i in range(pixesX*pixesY*3):
            
            tempArr[i] = int(''.join(temp2List[8*i:8*(i+1)]), 2)
        
        #sys.stdout.flush() 
        
        tempArr = tempArr.reshape(pixesX, pixesY, 3).astype(np.uint8) # 不加会模糊   
        showImage(tempArr, "image_after_decreption.bmp") 
    
                    
    def imageEncre(hidedImageFile, hidingImageFile):
        # 可视化隐藏前图片
        #imageArrBefore = mpimg.imread(hidingImageFile)
        #showImage(imageArrBefore, "image before hiding")
        
        # 把要加密的图片转换成 0  1 数字
        print("加密前准备工作...")
        binList = image2Bin(hidedImageFile) 
        
        # 接下来把 0 与 1 藏进另一张图片
        print("开始加密...")
        imageArrAfter = hiding(binList, hidingImageFile)
        #print(imageArrAfter[:8,:,:])
        showImage(imageArrAfter, "image_after_encreption.bmp")
    
    def imageDecre(imageFile):
        print("解码中...")
        imerging(imageFile)
        
        
    if __name__ == "__main__":  
        #imageEncre("hided.jpg", "hiding.jpg") 
        imageDecre("image_after_encreption.bmp")
    
  • 相关阅读:
    02 基本介绍
    01 概述 网络分层
    04 可扩展
    Java 注解2
    03 高可用
    重拾安卓_00_资源帖
    JavaUtil_09_通用工具类-01_Hutool
    java支付宝开发-01-沙箱环境接入
    java支付宝开发-00-资源帖
    svn_学习_01_TortoiseSVN使用教程
  • 原文地址:https://www.cnblogs.com/zhoukui/p/8687973.html
Copyright © 2020-2023  润新知