在了解了一些基本的图像处理操作后,我们开始着手实现图像隐写术。
载入准备的图像
类似信号传输中的调制操作,我们可以把像素值简单的图像作为需要隐藏的图像,而像素值丰富的图像作为载体。
准备一张用于载体的图像「色彩内容可以相对丰富」:
准备一张用需要被隐藏的图像「使用黑白色的文字内容」:
在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()