首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从python中的二进制文件中重建图像?

如何从python中的二进制文件中重建图像?
EN

Stack Overflow用户
提问于 2022-09-29 13:34:12
回答 1查看 127关注 0票数 0

我试图通过创建一个程序,用python模块将图像转换为二进制文件,从而在python中创建一个stegnography技术的示例。一旦转换,它将从每个像素值中删除最不重要的比特,并将其更改为编码跨越一定数量字节的消息;它将这样做,同时(理论上)保持文件的大致大小并保持图像的大部分外观。

然而,我遇到了一个问题,在这个问题上,我无法用剩下的数据重建图像或任何图像。

代码语言:javascript
复制
#secret message to be injected into the final bits.
injection = '0111001101100101011000110111001001100101011101000010000001101101011001010111001101110011011000010110011101100101001000000110100101101110011010100110010101100011011101000110100101101111011011100010000001101101011011110110110101100101011011100111010000100000011010000110010101101000011001010110100001100101011010000110010101101000011001010110100001100101'
injection_array=[]


count = 0
#loop to create an array of characters for the injection
for char in injection:
    injection_array.append(injection[count])
    count += 1
injectioncount = 0
count = 0
#loop to replace each bit with the desired injection
for element in pixel_bin:
    cached_element = pixel_bin[count]
    lsb_strip = cached_element[:-1]
    lsb_replace = lsb_strip + injection_array[injectioncount]
    pixel_bin[count] = lsb_replace
    count += 1
    injectioncount += 1
    if injectioncount == len(injection):
        break

#dumps outputted value for comparison with a control file of original pixel values
with open("comparison.json","w") as f:
    json.dump(pixel_bin,f, indent=2)

这就是我所能得到的。它的输出是一个列表,其中包含了变化的二进制序列,最后的位被改变了。

首先,我是这样获得像素数据的:

代码语言:javascript
复制
def bincon(image):

from PIL import Image
count = 0
pixel_binaries = []
im = Image.open(image, 'r')

pix_val = list(im.getdata()) #outputs rgb tuples for every pixel
pix_val_flat = [x for sets in pix_val for x in sets] #flattens the list so that each list item is just one rgb value

for elements in pix_val_flat: #converts each rgb value into binary
    pixel_binaries.append(bin(pix_val_flat[count]))
    count += 1

return pixel_binaries

我将如何将收集到的数据重构成类似于程序输入的图像?

编辑-尝试im_out = Image.fromarray(array_data_is_stored_in)方法确实返回一个图像文件,该文件打开,但不包含数据,当然不是原始图像。

EN

回答 1

Stack Overflow用户

发布于 2022-09-30 08:21:07

您发布的代码不是一个最小的可重复的示例,因此很难诊断问题是什么。

但是,基本方法是将图像读取到Numpy数组中。该数组为x,y (2d)数组,用于每个层/颜色。

Numpy在数组上有一个flatten()reshape()方法。这意味着,在迭代数组以更改每个像素之前,可以将其扁平化。然后在修改后再重新塑造它。

这可能是什么样子的一个例子:

代码语言:javascript
复制
from pathlib import Path
from typing import List

import imageio.v3 as iio
import numpy as np

secret_bit = 0


def max_msg_len(data: np.ndarray) -> int:
    row_size, column_size, layers = data.shape
    return (row_size * column_size * layers) // 8


def text_to_bits(txt: str) -> List[bool]:
    data = txt.encode()
    bin_str = "".join([f"{x:08b}" for x in data])
    bits = [x == "1" for x in bin_str]
    return bits


def bits_to_text(bits: List[bool]) -> bytes:
    data = bytearray()
    for x in range(0, (len(bits) // 8 * 8), 8):
        char = int("".join(["1" if i else "0" for i in bits[x: x + 8]]), 2)
        data.append(char)
    return_str = "".join([x for x in data.decode() if x.isprintable()])
    return return_str


def read_file(filename: Path) -> np.ndarray:
    return iio.imread(filename)


def write_file(filename: Path, data: bytes) -> None:
    iio.imwrite(filename, data)


def extract_message(data: np.ndarray) -> List[bool]:
    flat_data = data.flatten()
    extracted_bits = []
    for pixel in range(len(flat_data)):
        value = flat_data[pixel]
        found_bit = get_bit(value, secret_bit)
        extracted_bits.append(found_bit)
    return extracted_bits


def embed_message(data: np.ndarray, bits: List[bool]) -> bytes:
    orig_shape = data.shape
    flat_data = data.flatten()
    idx = 0
    bit_len = len(bits)
    for pixel in range(len(flat_data)):
        value = flat_data[pixel]
        if pixel < bit_len:
            flat_data[pixel] = set_bit(value, secret_bit, bits[pixel])
        else:
            flat_data[pixel] = set_bit(value, secret_bit, False)
        idx += 1
    return flat_data.reshape(orig_shape)


def set_bit(octet: int, bit: int, value: bool) -> int:
    mask = 1 << bit
    octet &= ~mask
    if value:
        octet |= mask
    return octet


def get_bit(octet: int, bit: int) -> bool:
    value = octet >> bit
    value &= 1
    return bool(value)


def main(img_in: Path, img_out: Path, msg: str) -> None:
    print("Message to hide:", msg)
    msg_bits = text_to_bits(msg)
    # Read img file
    img_content = read_file(img_in)
    # Check message will fit in image file
    # print(max_msg_len(img_content), len(msg), msg_bits)
    if len(msg) > max_msg_len(img_content):
        print(
            f"Message too long for image file. "
            f"Can only have {max_msg_len(img_content)} characters"
        )
        exit()
    # Modify data
    new_data = embed_message(img_content, msg_bits)
    # Check message can be extracted
    extracted_bits = extract_message(new_data)
    print("Message in new image:", bits_to_text(extracted_bits))
    # Save to file
    write_file(img_out, new_data)
    # Read from secret file
    img_content = read_file(img_out)
    read_bits = extract_message(img_content)
    print(f"From {img_out.name} read: {bits_to_text(read_bits)}")


if __name__ == "__main__":
    # Files
    data_dir = Path(__file__).parent.joinpath("data")
    original_png = data_dir.joinpath("gnome-xterm.png")
    secret_png = data_dir.joinpath("secret.png")
    # Message
    txt_to_hide = "secret message to hide hehehe"
    main(original_png, secret_png, txt_to_hide)

这在终端中提供了以下输出:

代码语言:javascript
复制
Message to hide: secret message to hide hehehe
Message in new image: secret message to hide hehehe
From secret.png read: secret message to hide hehehe

前、后图像如下:

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

https://stackoverflow.com/questions/73896442

复制
相关文章

相似问题

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