如何使用 Python 隐藏图像中的数据

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

ac18e17a8534a9b346bb25a1ece0461b.png

隐写术是在任何文件中隐藏秘密数据的艺术。

秘密数据可以是任何格式的数据,如文本甚至文件。简而言之,隐写术的主要目的是隐藏任何文件(通常是图像、音频或视频)中的预期信息,而不实际改变文件的外观,即文件外观看起来和以前一样。

在这篇文章中,我们将重点学习基于图像的隐写术,即在图像中隐藏秘密数据。

但在深入研究之前,让我们先看看图像由什么组成:

  1. 像素是图像的组成部分。

  2. 每个像素包含三个值:(红色、绿色、蓝色)也称为 RGB 值。

  3. 每个 RGB 值的范围从 0 到 255。

现在,让我们看看如何将数据编码和解码到我们的图像中。


编码

有很多算法可以用来将数据编码到图像中,实际上我们也可以自己制作一个。在这篇文章中使用的一个很容易理解和实现的算法。

算法如下:

  1. 对于数据中的每个字符,将其 ASCII 值转换为 8 位二进制 [1]。

  2. 一次读取三个像素,其总 RGB 值为 3*3=9 个。前八个 RGB 值用于存储一个转换为 8 位二进制的字符。

  3. 比较相应的RGB值和二进制数据。如果二进制数字为 1,则 RGB 值将转换为奇数,否则为偶数。

  4. 第 9 个值确定是否应该读取更多像素。如果有更多数据要读取,即编码或解码,则第 9 个像素变为偶数;否则,如果我们想停止进一步读取像素,那就让它变得奇数。

重复这个过程,直到所有数据都被编码到图像中。


例子

假设要隐藏的消息是‘Hii’。

消息是三个字节,因此,对数据进行编码所需的像素为 3 x 3 = 9。考虑一个 4 x 3 的图像,总共有 12 个像素,这足以对给定的数据进行编码。

[(27, 64, 164), (248, 244, 194), (174, 246, 250), (149, 95, 232),
(188, 156, 169), (71, 167, 127), (132, 173, 97), (113, 69, 206),
(255, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]


第 1 步

H 的 ASCII 值为 72 ,其二进制等效值为 01001000 。


第 2 步

读取前三个像素。

(27, 64, 164), (248, 244, 194), (174, 246, 250)


第 3 步

现在,将像素值更改为奇数为 1,偶数为 0,就像在二进制等效数据中一样。

例如,第一个二进制数字是0,第一个 RGB 值是 27 ,它需要转换为偶数,这意味着 26 。类似地,64 被转换为 63 因为下一个二进制数字是1 所以 RGB 值应该是奇数。

因此,修改后的像素为:

(26, 63, 164), (248, 243, 194), (174, 246, 250)


第4步

由于我们必须对更多数据进行编码,因此最后一个值应该是偶数。同样,i可以在这个图像中进行编码。

通过执行 +1 或 -1 使像素值成为奇数/偶数时,我们应该注意二进制条件。即像素值应大于或等于 0 且小于或等于 255 。

新图像将如下所示:

[(26, 63, 164), (248, 243, 194), (174, 246, 250), (148, 95, 231),
(188, 155, 168), (70, 167, 126), (132, 173, 97), (112, 69, 206),
(254, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]


解码

对于解码,我们将尝试找到如何逆转之前我们用于数据编码的算法。

  1. 同样,一次读取三个像素。前 8 个 RGB 值为我们提供了有关机密数据的信息,第 9 个值告诉我们是否继续前进。

  2. 对于前八个值,如果值为奇数,则二进制位为 1 ,否则为 0 。

  3. 这些位连接成一个字符串,每三个像素,我们得到一个字节的秘密数据,这意味着一个字符。

  4. 现在,如果第 9 个值是偶数,那么我们继续一次读取三个像素,否则,我们停止。

例如

让我们开始一次读取三个像素。

考虑我们之前编码的图像。

[(26, 63, 164), (248, 243, 194), (174, 246, 250), (148, 95, 231),
(188, 155, 168), (70, 167, 126), (132, 173, 97), (112, 69, 206),
(254, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]


第1步

我们首先读取三个像素:

[(26, 63, 164), (248, 243, 194), (174, 246, 250)


第2步

读取第一个值:26,它是偶数,因此二进制位是 0 。类似地,对于 63 ,二进制位是 1 ,对于 164 它是 0 。这个过程一直持续到 8 个 RGB 值。


第 3 步

将所有二进制值连接后,我们最终得到二进制值:01001000。最终的二进制数据对应于十进制值 72,在 ASCII 中,它代表字符 H 。


第 4 步

由于第 9 个值是偶数,我们重复上述步骤。当遇到的第 9 个值是奇数时,我们停止。

结果,我们得到了原始信息,即 Hii 。

上述算法的 Python 程序如下:

# Python program implementing Image Steganography


# PIL module is used to extract
# pixels of image and modify it
from PIL import Image


# Convert encoding data into 8-bit binary
# form using ASCII value of characters
def genData(data):


        # list of binary codes
        # of given data
        newd = []


        for i in data:
            newd.append(format(ord(i), '08b'))
        return newd


# Pixels are modified according to the
# 8-bit binary data and finally returned
def modPix(pix, data):


    datalist = genData(data)
    lendata = len(datalist)
    imdata = iter(pix)


    for i in range(lendata):


        # Extracting 3 pixels at a time
        pix = [value for value in imdata.__next__()[:3] +
                                imdata.__next__()[:3] +
                                imdata.__next__()[:3]]


        # Pixel value should be made
        # odd for 1 and even for 0
        for j in range(0, 8):
            if (datalist[i][j] == '0' and pix[j]% 2 != 0):
                pix[j] -= 1


            elif (datalist[i][j] == '1' and pix[j] % 2 == 0):
                if(pix[j] != 0):
                    pix[j] -= 1
                else:
                    pix[j] += 1
                # pix[j] -= 1


        # Eighth pixel of every set tells
        # whether to stop ot read further.
        # 0 means keep reading; 1 means thec
        # message is over.
        if (i == lendata - 1):
            if (pix[-1] % 2 == 0):
                if(pix[-1] != 0):
                    pix[-1] -= 1
                else:
                    pix[-1] += 1


        else:
            if (pix[-1] % 2 != 0):
                pix[-1] -= 1


        pix = tuple(pix)
        yield pix[0:3]
        yield pix[3:6]
        yield pix[6:9]


def encode_enc(newimg, data):
    w = newimg.size[0]
    (x, y) = (0, 0)


    for pixel in modPix(newimg.getdata(), data):


        # Putting modified pixels in the new image
        newimg.putpixel((x, y), pixel)
        if (x == w - 1):
            x = 0
            y += 1
        else:
            x += 1


# Encode data into image
def encode():
    img = input("Enter image name(with extension) : ")
    image = Image.open(img, 'r')


    data = input("Enter data to be encoded : ")
    if (len(data) == 0):
        raise ValueError('Data is empty')


    newimg = image.copy()
    encode_enc(newimg, data)


    new_img_name = input("Enter the name of new image(with extension) : ")
    newimg.save(new_img_name, str(new_img_name.split(".")[1].upper()))


# Decode the data in the image
def decode():
    img = input("Enter image name(with extension) : ")
    image = Image.open(img, 'r')


    data = ''
    imgdata = iter(image.getdata())


    while (True):
        pixels = [value for value in imgdata.__next__()[:3] +
                                imgdata.__next__()[:3] +
                                imgdata.__next__()[:3]]


        # string of binary data
        binstr = ''


        for i in pixels[:8]:
            if (i % 2 == 0):
                binstr += '0'
            else:
                binstr += '1'


        data += chr(int(binstr, 2))
        if (pixels[-1] % 2 != 0):
            return data


# Main Function
def main():
    a = int(input(":: Welcome to Steganography ::\n"
                        "1. Encode\n2. Decode\n"))
    if (a == 1):
        encode()


    elif (a == 2):
        print("Decoded Word :  " + decode())
    else:
        raise Exception("Enter correct input")


# Driver Code
if __name__ == '__main__' :


    # Calling main function
    main()

程序中使用的模块是 PIL ,它代表Python 图像库,它使我们能够在 Python 中对图像执行操作。


程序执行

e76649256d507d233b601fb57b467c44.png

数据编码

a6e5a4d719b6fe80faa898116eef1ff2.png

数据解码

输入图像

3010409d3c62188c52549fff6ebdae90.png

输出图像

708db8e4f6cfe38fde378468dfce5e07.png


局限性

该程序可能无法对 JPEG 图像按预期处理,因为 JPEG 使用有损压缩,这意味着修改像素以压缩图像并降低质量,因此会发生数据丢失。


参考

  1. https://www.geeksforgeeks.org/program-decimal-binary-conversion/

  2. https://www.geeksforgeeks.org/working-images-python/

  3. https://dev.to/erikwhiting88/let-s-hide-a-secret-message-in-an-image-with-python-and-opencv-1jf5

  4. A code along with the dependencies can be found here: https://github.com/goelashwin36/image-steganography

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

8c46300dcbcd39f5d399af3bab62a64c.png

fbc1c3bc31d3495258df0c935f7c77d1.png

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白学视觉

您的赞赏是我们坚持下去的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值