published on in Python

隐写术・图像隐写术

返回教程主页

上篇 隐写术・图像处理

在了解了一些基本的图像处理操作后,我们开始着手实现图像隐写术。

载入准备的图像

类似信号传输中的调制操作,我们可以把像素值简单的图像作为需要隐藏的图像,而像素值丰富的图像作为载体。

准备一张用于载体的图像「色彩内容可以相对丰富」:

准备一张用需要被隐藏的图像「使用黑白色的文字内容」:

在Python中载入它们:

bg = Image.open('container.jpg')
fg = Image.open('python.jpg')

对载体图像进行预处理

我们需要预处理载体图像为即将被隐藏的内容图像腾出一点点空间。在这里我们将载体图像中的每一个不为偶数的像素值减去一:

def preprocess(frame:Image.Image):
    image = frame.convert('RGB')
    array = np.array(image)
    array -= array % 2
    return array

container = preprocess(bg)

frame.convert('RGB')用于确保输入图像的色彩模式为RGB通道模式。

对内容图像进行二值化

我们将色彩简单的内容图像进行二值化,使之成为像素值仅为0与1的图像:

def to_binary(frame:Image.Image, threshold:int=127):
    gray   = frame.convert('L')
    array  = np.array(gray)
    binary = (array > threshold).astype(np.uint8)
    return binary

binary = to_binary(fg)

frame.convert('L')用于将输入图像转换为灰度图像。

将二值化后的内容载入到载体图像中

在得到处理过的载体图像以及二值化的内容图像后,我们可以将其相加得到最终图像并保存到本地:

def merge_image(container:np.ndarray, binary:np.ndarray):
    r1, c1 = container.shape[0], container.shape[1]
    r2, c2 = binary.shape[0], binary.shape[1]
    r, c = min(r1, r2), min(c1, c2)
    final = np.copy(container)
    final[:r, :c, :] += binary[:r, :c, None]
    return final

final = merge_image(container, binary)
final_img = Image.fromarray(final)
final_img.save('merged.png')

使用png格式存储图像,能够确保图像在被压缩时,隐藏的内容信息不会被抹除,且最终得到的图像文件也不会太大。

尝试从融合后的图像中解析出内容

在完成融合操作后,我们还得通过解析内容来确认操作是否成功:

def get_binary(frame:Image.Image):
    array = np.array(frame)
    array %= 2
    array *= 255
    image = Image.fromarray(array)
    return image

merged = Image.open('merged.png')
_binary = get_binary(merged)
_binary.show()

代码清单

from PIL import Image
import numpy as np


def preprocess(frame:Image.Image):
    image = frame.convert('RGB')
    array = np.array(image)
    array -= array % 2
    return array

def to_binary(frame:Image.Image, threshold:int=127):
    gray   = frame.convert('L')
    array  = np.array(gray)
    binary = (array > threshold).astype(np.uint8)
    return binary

def merge_image(container:np.ndarray, binary:np.ndarray):
    r1, c1 = container.shape[0], container.shape[1]
    r2, c2 = binary.shape[0], binary.shape[1]
    r, c = min(r1, r2), min(c1, c2)
    final = np.copy(container)
    final[:r, :c, :] += binary[:r, :c, None]
    return final

def get_binary(frame:Image.Image):
    array = np.array(frame)
    array %= 2
    array *= 255
    image = Image.fromarray(array)
    return image

bg = Image.open('container.jpg')
fg = Image.open('python.jpg')

container = preprocess(bg)
binary = to_binary(fg)

final = merge_image(container, binary)
final_img = Image.fromarray(final)
final_img.save('merged.png')

merged = Image.open('merged.png')
_binary = get_binary(merged)
_binary.show()

下篇 隐写术・QRCode