LSB最低有效位数字水印嵌入算法
本篇博客主要介绍了基于OpenCV的信息隐藏技术,通过在载体图像中嵌入文字信息,生成水印图像,并提供解密方法还原隐藏的信息。
算法介绍:
LSB隐写(最低有效位的隐写),是指通过改变图片中像素的最低位来实现信息的隐藏的。这种隐写方式需要图片是无压缩的位图,因此一般用于bmp和png图片。
加密过程与解密过程:
思路
- 创建一个单通道的灰度图像作为载体图像。
- 初始化参数,包括字体、缩放比例和文字位置等。
- 在载体图像上使用指定的字体和参数写入黑色文字。
- 创建水印图像并调整大小为与载体图像相同的尺寸。
- 遍历载体图像和水印图像的每个像素点,根据最后一位的奇偶性改变载体图像的像素值,从而嵌入水印信息。
- 保存生成的水印图像。
- 提供解密方法,遍历水印图像的每个像素点,根据像素值的奇偶性还原隐藏的信息。
- 保存解密后的图像。
函数设计
-
convert_last_bit:将载体图像像素值根据水印图像的像素值的奇偶性进行调整,用于信息嵌入。
#如果是用==0 或者 ==255 判断会导致字符边缘虚化
#根据10进制数值是单数 2进制最后一位是1 否则是0
#通过+1 -1 对数值进行更改 实现信息隐写参数:
- a: 载体图像的像素值
- b: 水印图像的像素值
- 返回值:调整后的像素值
def convert_last_bit(a, b): if b <100 and a % 2 == 1: a = a - 1 if b >200 and a % 2 == 0: a = a + 1 return a
-
create_image_with_text:创建带有指定文字的灰度图像。
这个函数用于创建一个灰度图像,并在图像上嵌入指定的文字。函数首先创建一个尺寸为(400, 400)的灰度图像,像素值初始化为255(白色)。然后,根据函数参数设定了字体类型、缩放比例和线条粗细度。接下来,通过调用cv2.getTextSize()
函数获取指定文字的尺寸大小。然后,根据图像和文字尺寸的计算,确定文字在图像上的起始位置坐标。最后,使用cv2.putText()
函数将黑色文字嵌入到图像中,生成带有文字的灰度图像,并保存为文件2.png
。最后,返回生成的灰度图像。
参数:- text: 要嵌入的文字信息 返回值:生成的灰度图像
import cv2 import numpy as np def create_image_with_text(text): # 创建一个尺寸为(400, 400)、像素值为255(白色)的灰度图像 image = np.full((400, 400), 255, dtype=np.uint8) # 初始化参数 font_face = cv2.FONT_HERSHEY_SIMPLEX # 使用字体类型:OpenCV内置字体cv2.FONT_HERSHEY_SIMPLEX font_scale = 1.5 # 字体缩放比例 thickness = 4 # 文字线条的粗细度 # 获取文字的尺寸大小 text_size, _ = cv2.getTextSize(text, font_face, font_scale, thickness) # 计算文字在图像上的起始位置坐标 origin_x = (image.shape[1] - text_size[0]) // 3 origin_y = (image.shape[0] + text_size[1]) // 2 # 在图像上写入黑色文字 cv2.putText(image, text, (origin_x, origin_y), font_face, font_scale, 0, thickness) # 将生成的图像保存为文件 cv2.imwrite("2.png", image) # 返回生成的灰度图像 return image
- text: 要嵌入的文字信息 返回值:生成的灰度图像
-
generate:生成带有水印的图像。
这个函数用于生成带有水印的图像。函数首先创建一个大小与载体图像相同的全零图像zero_img
,用于存储生成的水印图像。然后,调用create_image_with_text
函数生成水印图像watermark_img
。接下来,根据载体图像和水印图像的尺寸差异,调整水印图像的大小,使其与zero_img
图像大小相同。然后,使用双线性插值法将水印图像进行调整。接着,通过遍历载体图像的每个像素点,获取当前像素点的载体图像和水印图像的像素值。最后,将载体图像的最后一位比特位替换为水印图像的像素值,并将结果存入zero_img
图像中。最后,将生成的水印图像保存为文件watermarked_img.png
,并打印提示信息。
参数:- carry_img: 载体图像,灰度图像
- msg: 要嵌入的文字信息 功能:根据载体图像和文字信息生成水印图像,并将水印信息嵌入载体图像中
def generate(carry_img, msg): # 创建一个全零图像,尺寸与载体图像相同,用于存储生成的水印图像 zero_img = np.zeros((carry_img.shape[0], carry_img.shape[1]), dtype=np.uint8) # 调用create_image_with_text函数生成水印图像 watermark_img = create_image_with_text(msg) # 调整水印图像大小,使其与zero_img图像大小相同 resize_scale_x = int(carry_img.shape[0] / watermark_img.shape[0]) resize_scale_y = int(carry_img.shape[1] / watermark_img.shape[1]) resized_watermark_img = cv2.resize(watermark_img, (0, 0), fx=resize_scale_x, fy=resize_scale_y) # 遍历载体图像的每个像素点 for i in range(carry_img.shape[0]): for j in range(carry_img.shape[1]): # 获取当前像素点的载体图像和水印图像的像素值 carry_pixel = carry_img[i, j] watermark_pixel = resized_watermark_img[i, j] # 将载体图像的最后一位比特位替换为水印图像的像素值,并将结果存入zero_img图像中 zero_img[i][j] = convert_last_bit(carry_pixel, watermark_pixel) # 将生成的水印图像保存为文件 cv2.imwrite('watermarked_img.png', zero_img) # 打印提示信息 print('水印图片已生成')
-
decrypt:解密水印图像还原隐藏的信息。
这个函数用于解密带有水印的图像。函数首先创建一个大小与水印图像相同的全零图像zero_img
,用于存储解密后的图像。然后,通过遍历水印图像的每个像素点,获取当前像素点的水印图像的像素值。接下来,判断当前像素值的最后一位比特位是0还是1,如果是0,则将该像素值设为0,否则设为255。然后,将处理后的像素值存入zero_img
图像中。最后,将解密后的图像保存为文件decrypt.png
,并打印提示信息。
参数:- watermarked_img: 带有水印的图像,灰度图像 功能:根据水印图像的像素值奇偶性,还原隐藏的信息并生成解密后的图像
def decrypt(watermarked_img): # 创建一个全零图像,尺寸与水印图像相同,用于存储解密后的图像 zero_img = np.zeros((watermarked_img.shape[0], watermarked_img.shape[1]), dtype=np.uint8) # 遍历水印图像的每个像素点 for i in range(watermarked_img.shape[0]): for j in range(watermarked_img.shape[1]): # 获取当前像素点的水印图像的像素值 ij_pixel = watermarked_img[i][j] # 判断当前像素值的最后一位比特位是0还是1,如果是0,则将该像素值设为0,否则设为255 if ij_pixel % 2 == 0: ij_pixel = 0 else: ij_pixel = 255 # 将处理后的像素值存入zero_img图像中 zero_img[i][j] = ij_pixel # 将解密后的图像保存为文件 cv2.imwrite('decrypt.png', zero_img) # 打印提示信息 print('解密图片已生成')
- watermarked_img: 带有水印的图像,灰度图像 功能:根据水印图像的像素值奇偶性,还原隐藏的信息并生成解密后的图像
源码(单通道灰度图)
import datetime
import cv2
import numpy as np
def convert_last_bit(a, b):
#如果是用==0 或者 ==255 判断会导致字符边缘虚化
#根据10进制数值是单数 2进制最后一位是1 否则是0
#通过+1 -1 对数值进行更改 实现信息隐写
if b <100 and a % 2 == 1:
a = a - 1
if b >200 and a % 2 == 0:
a = a + 1
return a
def create_image_with_text(text):
# 创建一个单通道(灰度)的图像
image = np.full((400, 400), 255, dtype=np.uint8)
# 初始化参数
font_face = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 1.5
thickness = 4
text_size, _ = cv2.getTextSize(text, font_face, font_scale, thickness)
origin_x = (image.shape[1] - text_size[0]) // 3
origin_y = (image.shape[0] + text_size[1]) // 2
# 在图像上写入黑色文字
cv2.putText(image, text, (origin_x, origin_y), font_face, font_scale, 0, thickness)
cv2.imwrite("2.png",image)
return image
def generate(carry_img, msg):
zero_img = np.zeros((carry_img.shape[0], carry_img.shape[1]), dtype=np.uint8)
watermark_img = create_image_with_text(msg)
# 调整水印图片大小与zero_img相同
resize_scale_x = int(carry_img.shape[0] / watermark_img.shape[0])
resize_scale_y = int(carry_img.shape[1] / watermark_img.shape[1])
resized_watermark_img = cv2.resize(watermark_img, (0, 0), fx=resize_scale_x, fy=resize_scale_y)
for i in range(carry_img.shape[0]):
for j in range(carry_img.shape[1]):
# 获取载体图像和水印图像的像素值
carry_pixel = carry_img[i, j]
watermark_pixel = resized_watermark_img[i, j]
zero_img[i][j] = convert_last_bit(carry_pixel, watermark_pixel)
cv2.imwrite('watermarked_img.png', zero_img)
print('水印图片已生成')
def decrypt(watermarked_img):
zero_img = np.zeros((watermarked_img.shape[0], watermarked_img.shape[1]), dtype=np.uint8)
for i in range(watermarked_img.shape[0]):
for j in range(watermarked_img.shape[1]):
# 获取载体图像和水印图像的像素值
ij_pixel = watermarked_img[i][j]
if ij_pixel % 2 == 0:
ij_pixel = 0
else:
ij_pixel = 255
zero_img[i][j] = ij_pixel
cv2.imwrite('decrypt.png', zero_img)
print('解密图片已生成')
# 交互式调用
carry_img_path = input("请输入载体图像的路径:")
msg = input("请输入要嵌入的文字信息:")
# 加载载体图像
carrier_image = cv2.imread(carry_img_path, 0)
# 生成水印图像
generate(carrier_image, msg)
# 解密水印图像
watermarked_img_path = "watermarked_img.png"
watermarked_image = cv2.imread(watermarked_img_path, 0)
decrypt(watermarked_image)
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
源码(RGB图片B通道加密黑白水印)
import cv2
import numpy as np
def convert_last_bit(a, b):
if b < 120 and a % 2 == 1:
a = a - 1
if b > 120 and a % 2 == 0:
a = a + 1
return a
def create_image_with_text(text):
# 创建一个三通道(RGB)的图像
image = np.full((400, 400, 3), 255, dtype=np.uint8)
# 初始化参数
font_face = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 1.5
thickness = 4
text_size, _ = cv2.getTextSize(text, font_face, font_scale, thickness)
origin_x = (image.shape[1] - text_size[0]) // 3
origin_y = (image.shape[0] + text_size[1]) // 2
# 在图像上写入黑色文字
cv2.putText(image, text, (origin_x, origin_y), font_face, font_scale, (0, 0, 0), thickness)
cv2.imwrite("2.png", image)
return image
def generate(carry_img, msg):
zero_img = np.zeros((carry_img.shape[0], carry_img.shape[1], 3), dtype=np.uint8)
watermark_img = create_image_with_text(msg)
resized_watermark_img = cv2.resize(watermark_img, (carry_img.shape[1], carry_img.shape[0]))
for i in range(carry_img.shape[0]):
for j in range(carry_img.shape[1]):
# 获取载体图像和水印图像的像素值
carry_pixel = carry_img[i, j]
watermark_pixel = resized_watermark_img[i, j]
# 将B颜色通道的最后一位与水印像素值进行加密
zero_img[i][j][0] = convert_last_bit(carry_pixel[0], watermark_pixel[0])
# 其他颜色通道保持不变
zero_img[i][j][1] = carry_pixel[1]
zero_img[i][j][2] = carry_pixel[2]
cv2.imwrite('watermarked_img.png', zero_img)
print('水印图片已生成')
def decrypt(watermarked_img):
zero_img = np.zeros((watermarked_img.shape[0], watermarked_img.shape[1]), dtype=np.uint8)
for i in range(watermarked_img.shape[0]):
for j in range(watermarked_img.shape[1]):
# 获取载体图像和水印图像的像素值
ij_pixel = watermarked_img[i][j][0]
# 解密B颜色通道的最后一位
if ij_pixel % 2 == 0:
ij_pixel = 0
else:
ij_pixel = 255
# 其他颜色通道保持不变
zero_img[i][j] = ij_pixel
cv2.imwrite('decrypt.png', zero_img)
print('解密图片已生成')
# 交互式调用
carry_img_path = input("请输入载体图像的路径:")
msg = input("请输入要嵌入的文字信息:")
# 加载载体图像
carrier_image = cv2.imread(carry_img_path)
# 生成水印图像
generate(carrier_image, msg)
# 解密水印图像
watermarked_img_path = "watermarked_img.png"
watermarked_image = cv2.imread(watermarked_img_path)
decrypt(watermarked_image)
总结:
全靠GPT:albge.aichatos.com/#/chat/1690172938143