首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用PIL的Python隐写器

使用PIL的Python隐写器
EN

Code Review用户
提问于 2017-06-07 13:19:41
回答 1查看 437关注 0票数 7

我使用Python图像库制作了一个Python隐写器。它基本上对图像每个像素中红色内容的最后n个比特中的二进制文本进行编码。这是我的代码,请提出一些改进建议。

代码语言:javascript
复制
from PIL import Image

import os

def str2bin(message):
    binary = bin(int.from_bytes(message.encode('utf-8'), 'big'))
    return binary[2:]

def bin2str(binary):
    n = int(binary, 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()

def hide(filename, message, bits=2):
    image = Image.open(filename)
    binary = str2bin(message) + '00000000'

    if (len(binary)) % 8 != 0:
        binary = '0'*(8 - ((len(binary)) % 8)) + binary

    data = list(image.getdata())

    newData = []

    index = 0
    for pixel in data:
        if index < len(binary):
            pixel = list(pixel)
            pixel[0] >>= bits
            pixel[0] <<= bits
            pixel[0] += int('0b' + binary[index:index+bits], 2)
            pixel = tuple(pixel)
            index += bits

        newData.append(pixel)

    image.putdata(newData)
    image.save('\\'.join(filename.split('\\')[0:-1]) + '/coded-'+os.path.basename(filename), 'PNG')

    return len(binary)

def unhide(filename, bits=2):
    image = Image.open(filename)
    data = image.getdata()

    binary = ''

    index = 0

    while not (len(binary) % 8 == 0 and binary[-8:] == '00000000'):
        value = '00000000' + bin(data[index][0])[2:]
        binary += value[-bits:]
        index += 1

    message = bin2str(binary)
    return message


if __name__ == '__main__':

    file = open('tmiab.txt', encoding='utf-8')

    hide('E:\\Python\\Steganography\\img.png', file.read(), 2)
    print(unhide('E:\\Python\\Steganography\\coded-img.png', 2)[:10000])

我能够编码小说中的三个人在一艘船在1600乘1200像素的图像,只需更换最后两位。

我正在寻找一些改进,如减少时间消耗。

请帮帮忙。谢谢。

EN

回答 1

Code Review用户

回答已采纳

发布于 2017-06-10 08:12:14

时间消耗建议

执行list(Image.open(filename).getdata())意味着在开始任何处理之前读取整个图像。这意味着时间和内存开销按像素的顺序排列。看起来,您每次只需要处理一个像素,因此您可以直接迭代getdata()的结果,将像素视为流。在处理更大的数据结构时,这一点变得非常重要,特别是当整个数据无法存储在内存中时。如果getdata()的结果对您的目的不是最好的,那么就会有许多对图像中像素进行迭代的其他方法。迭代文本数据可能不是那么重要(因为数据应该要小得多),但也会比一次性阅读更好。

您目前正在进行许多值转换,从UTF-8字符串到二进制和back,二进制到int和back,以及像素到列表(大概是分离颜色值)。避免这些转换会大大提高程序的速度。一般来说,确定一个单一的“数据交换类型”是个好主意,在这种情况下,整数是一个显而易见的选择--它们很容易映射到文本和像素值,而且处理起来非常快。

一般建议

您有可选的参数,这些参数除了默认值之外,从来不与任何其他参数一起使用。这增加了混乱,并使我怀疑函数是否会做正确的事情,如果调用其他任何东西。

使用argparse允许指定输入数据文件和图像文件。这使得程序更加通用,可测试性更强。

驱动此代码的测试应该指出该程序的一些限制:

  • 如果数据不适合内存呢?
  • 如果图像太小,无法对整个文本进行编码,该怎么办?
  • 如果用户指定bits > 8怎么办?
  • 为什么假设UTF-8而不是仅仅编码任意字节值?UTF-8的额外限制使确保数据被正确编码和解码变得更加困难,并限制了程序的实用性。例如,您可能希望在另一个图像中编码图像。
  • 如果图像不是每像素8位呢?
  • 未经修改的像素与隐写像素之间的最大感知颜色距离是多少?也就是说,一个人是否能够察觉到颜色的差异,例如在一张高质量的照片上,上面有大的均匀的补丁,或者一张颜色一致的照片?

pep8是一个很好的工具,可以确保您的代码是惯用的Python。例如:在Python变量中,按约定名总是under_scored

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/165163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档