Python图像隐写术:基于RGB像素值的编码与解码详解

白榆
白榆
发布时间:2026-10-16| 4人浏览过
原创

本文详解如何使用Python实现图像隐写术,通过在RGB像素的最低有效位中修改奇偶性来隐藏文本数据。文章介绍了基于ASCII转二进制的编码算法,演示了如何逐个像素修改数值以存储信息,并提供了完整的解码逻辑。此外,还分析了该技术在JPEG等有损压缩格式下的局限性,适合希望了解基础数据隐藏技术的开发者参考。

隐写术是一种在各类文件中秘密隐藏数据的技术。

被隐藏的数据可以是文本或文件等多种格式。其核心目标是在不改变文件外观的前提下,将预期信息嵌入到图像、音频或视频等载体中,使文件在视觉上保持原样。

本文将重点探讨基于图像的隐写术,即如何在图像中嵌入秘密数据。

在深入具体实现之前,首先需要了解图像的基本构成要素:

1. 像素是构成图像的基本单元。

2. 每个像素由三个颜色通道值组成,即红(Red)、绿(Green)、蓝(Blue),统称为RGB值。

3. 每个RGB通道的取值范围介于0到255之间。

接下来,我们将探讨如何将数据编码进图像以及如何从中解码出来。

编码过程

存在多种将数据编码到图像中的算法,开发者甚至可以根据需求定制算法。本文采用一种易于理解且实现简单的编码方案。

具体算法步骤如下:

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

2. 每次读取三个像素,共涉及9个RGB通道值。其中前8个RGB值用于存储一个字符对应的8位二进制数据。

3. 对比对应的RGB值与二进制位:若二进制位为1,则将该RGB值调整为奇数;若为0,则调整为偶数。

4. 第9个RGB值用于控制读取流程:若仍有数据需编码或解码,将该值设为偶数以继续读取;若数据已处理完毕,将其设为奇数以停止读取。

重复上述步骤,直至所有数据均被编码至图像中。

实例演示

假设需要隐藏的消息为“Hii”。

该消息包含3个字节,因此编码所需像素数量为 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,则确保RGB值为奇数;若为0,则确保为偶数。

例如,第一个二进制位是0,对应的第一个RGB值27需改为偶数,即26。同理,下一个二进制位是1,对应的RGB值64需改为奇数63。

因此,修改后的像素数据如下:

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

第4步

由于仍需编码更多数据,最后一个(第9个)RGB值应设为偶数。以此类推,字符“i”也可按相同方式编码进图像。

在通过加减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. 对于前8个值,若RGB值为奇数,则对应的二进制位为1;若为偶数,则二进制位为0。

3. 将这些二进制位连接起来,每处理三个像素(即8个RGB值)即可还原出一个字节的秘密数据,对应一个字符。

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图像库),它提供了对图像像素进行提取和修改的功能。

程序执行流程

数据编码

数据解码

输入图像

输出图像

局限性分析

该程序可能无法在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. 包含依赖项的完整代码仓库:https://github.com/goelashwin36/image-steganography

本文介绍了如何使用Python在图像中隐藏数据。如需了解更多Python图像数据处理相关内容,欢迎查阅本站其他文章或继续关注后续更新,感谢支持!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。