admin 管理员组

文章数量: 1184232

数字图像

图像隐写(Image Steganography)

  • 引言
  • 空域隐写
  • 频域隐写
  • 调用python包隐写
  • 总结

引言

今天学习了图像隐写,图像隐写就是把信息隐藏写入到数字图像里面,一般情况下看不出有什么,需要去解析后才能获取隐藏的内容。然后自己写了下python代码实现下:1.从图像空域隐写信息;2.从图像频域隐写信息;3.用stegano包直接调用接口进行隐写。

空域隐写

显示器的标准格式就用(R,G,B)表示一个像素的颜色显示,其范围为黑色(0, 0, 0)~ 白色(255, 255, 255)。用每一个都是用8 bit的信息的表示,其中隐写的LSB(Least Significant Bits)算法就是用最后一个bit来写入信息而图像不至于失真太明显。

from PIL import Image, ImageDraw, ImageFont
import numpy as np
from matplotlib import pyplot as plt# 画一张跟原始图像一样大小的水印图像,把字符串用黑色微软雅黑14号大小循环画成水印图像
def draw_a_water_mark_img(img_size, img_mode, water_mark_str):image_draw = Image.new(img_mode, img_size,"white")draw = ImageDraw.Draw(image_draw)# 字体大小,用的是微软雅黑font_size = 14water_mark_size = len(water_mark_str)x_step_num = int(img_size[0] / font_size)y_step_num = int(img_size[1] / font_size)k = 0for j in range(y_step_num):for i in range(x_step_num):draw.text((i * font_size,j * font_size),water_mark_str[k%water_mark_size], font=ImageFont.truetype("msyh.ttc",font_size),fill="black")k=k+1return image_draw# 通过先右移再左移的移位操作使最后的1个bit为0,形成新的原始图像
def make_least_significant_bit_0(img):img_list = list(img.getdata())new_img_list = [(r >> 1 << 1, g >> 1 << 1, b >> 1 << 1) for [r, g, b] in img_list]new_img = Image.new(img.mode, img.size)new_img.putdata(new_img_list)    return new_img# 把水印图像设置到新的原始图像里
def set_msg_into_img_space(lsb_0_img, water_mark_img):lsb_0_enum = enumerate(list(lsb_0_img.getdata()))water_mark_list = list(water_mark_img.getdata())#(0, 0, 0)是黑色,(255, 255, 255)是白色,由于用笔画出来的并不一定都是黑色(阴影或者笔锋等造成),所以要用小于号二值化掉字体。有黑色字体的给最后一位加1,其他保持不变result = [(r, g, b) if (water_mark_list[index]<(255,255,255)) else (r|1, g|1, b|1) for index,(r, g, b) in lsb_0_enum]new_result = Image.new(lsb_0_img.mode, lsb_0_img.size)new_result.putdata(result)return new_result# 编码写入水印
def encode_img(img, water_mark_str):## 从空域上写入水印water_mark_img = draw_a_water_mark_img(img.size, img.mode, water_mark_str)lsb_0_img = make_least_significant_bit_0(img)encode_img = set_msg_into_img_space(lsb_0_img, water_mark_img) return encode_img# 从编码后的图像获取水印图像
def get_water_mark_from_img_space(img):img_enum = enumerate(list(img.getdata()))white_img = Image.new(img.mode, img.size, "white")decode_img_list = [(0,0,0) if (r&1==0 and g&1==0 and b&1==0) else (255,255,255) for index,[r, g, b] in img_enum]decode_img = Image.new(img.mode, img.size)decode_img.putdata(decode_img_list)return decode_imgimg = Image.open('lena.jpeg')
water_mark_str = "Copyright 2022 ***, All Rights Reserved."
encode_img = encode_img(img, water_mark_str)
decode_img = get_water_mark_from_img_space(encode_img)
encode_img.save("encode_space_img.png")
decode_img.save("decode_space_img.png")


频域隐写

把图像经过快速傅里叶变换后,再把高频部分移到图像中间,然后我们把水印图像写到高频的地方,如图像的左上角,因为高频地方的改变对图像的影响较小。然后再反傅里叶变换得到编码后的图像。

def set_msg_into_img_spectrum(img, water_mark_img):# 快速傅里叶变换f=np.fft.fft2(img)# 高频移至图像中间fshift = np.fft.fftshift(f)(wm_heigh, wm_width) = water_mark_img.size(img_width, img_heigh) = img.size# 水印图像不要大于原始图像的1/4if(wm_heigh > img_heigh/4 or wm_width > img_width/4):print("water_mark_img is not suitable")return#左上角添加水印fshift[0:wm_width,0:wm_heigh,:] = water_mark_img# 查看频谱信息# plt.imshow(np.abs(fshift).astype(np.uint8))# plt.show()# 傅里叶反变换ishift = np.fft.ifftshift(fshift)iimg = np.fft.ifft2(ishift)result = np.abs(iimg).astype(np.uint8)result_img = Image.fromarray(result)return result_imgdef get_water_mark_from_img_spectrum(img):f=np.fft.fft2(img)fshift = np.fft.fftshift(f)result = np.abs(fshift).astype(np.uint8)result_img = Image.fromarray(result)return result_imgdef encode_img(img, water_mark_str):## 从频域上写入水印(img_width, img_heigh) = img.sizewater_mark_img = draw_a_water_mark_img((int(img_width/4), int(img_heigh/4)), img.mode, water_mark_str)encode_img = set_msg_into_img_spectrum(img, water_mark_img)  return encode_img
encode_img = encode_img(img, water_mark_str)
decode_img = get_water_mark_from_img_spectrum(encode_img)
encode_img.save("encode_spectrum_img.png")
decode_img.save("decode_spectrum_img.png")



其实贴完图的频谱图像是下面这样的,后面经过一系列转化后,就变得上面的那样了。

调用python包隐写

from stegano import lsb
img = Image.open('lena.jpeg')
img_hide = lsb.hide(img, water_mark_str)
img_hide.save("img_hide.png")
open_img = Image.open("img_hide.png")
print(lsb.reveal(open_img))
Copyright 2022 ***, All Rights Reserved.

总结

你学废了吗?

本文标签: 数字图像