数字水印介绍
常见的图片水印多是在图片上附上文字、logo等信息,可以直观地看出来,除了这种水印外,好可以给图片加一种看不见的水印,比如说是文字信息。
实现原理
-
图像中的每个像素通常用RGB三个0~255的值来表示,转化为二进制就是00000000~11111111。
-
把每个值的最后一位全部设为零,这种变化人眼观察不到。
-
这样空出来的最后一位就可以用来存储信息。
-
提取信息的过程就是上述过程的逆:把像素值提取出来,选择最后一位,拼出信息。
代码实现
导入用到的包
from PIL import Image
import numpy as np
import functools
加密过程
def embedding_info(picname, savename, text):
text += '#%#' #在文本末端加入一个标记符,提取过程中以此为结束标记
# 读取图片
im = np.array(Image.open(picname))
rows, columns, colors = im.shape
embed = []
for c in text:
bin_sign = (bin(ord(c))[2:]).zfill(16) #(bin(ord(c))[2:])是转化为2进制, .zfiil(16)是原来字符右对齐,左边全部用0填充
for i in range(16):
embed.append(int(bin_sign[i]))
count = 0
for row in range(rows):
for col in range(columns):
for color in range(colors):
if count < len(embed):
im[row][col][color] = im[row][col][color] // 2 * 2 +embed[count] #用地板除乘以2,使得末尾数字为0,再把文本字符转化为2进制的数字填充进去
count += 1
Image.fromarray(im).save(savename)
解密过程
def extract_info(picname):
im = np.array(Image.open(picname))
rows, columns, colors = im.shape
text = ""
extract = np.array([], dtype = int)
count = 0
for row in range(rows):
for col in range(columns):
for color in range(colors):
extract = np.append(extract, im[row][col][color] % 2) #注1
count += 1
if count % 16 ==0:
bcode = functools.reduce(lambda x, y: str(x) + str(y), extract) #注2
cur_char = chr(int(bcode, 2)) #将2进制转化为字符
text += cur_char
if cur_char == '#' and text[:-3] == '#%#':
return text[-3:] #如果return语句被执行,就会退出当前函数体,结束提取过程
extract = np.array([], dtype = int)
注1:
np.append
是将传入的两个元素横着合并到一起,如np.append([1,2,3] , [9,8,7])
的输出是[1,2,3,4,9,8,7]
注2:functools.reduce(lambda x: x*2, [1,2,3,4])
的输出为(((1*2)*2)*2)*2
运行代码
def main():
text = "Hello, world!"
embedding_info('C:\\Users\\yyy\\Documents\\img_111.png', 'After.png', text)
extract_info('After.png')
if __name__ == '__main__':
main()
实现效果
原图 Before.png处理后 After.png
网友评论