【Python】简单的图片隐写术

图片隐写术,即在图片里非显式地嵌入信息,实现图片隐写有很多方法。

第一种方式(来自维基百科):

这里写图片描述

这里写图片描述

要从上图中获取下图的信息,只需要将上图色彩空间中的每个二进制数都只保留最后两位(即相当于与3做按位与计算),再将亮度层乘以85即可。用matlab实现这个操作很简单,代码如下所示:

test=imread('D:/tree.png');
for i=1:3
for j=1:200
for k=1:200
test(j,k,i)=bitand(test(j,k,i),3);
end
end
end
test=rgb2hsv(test);
for i=1:200
for j=1:200
test(i,j,3)=test(i,j,3)*85;
end
end
test=hsv2rgb(test);
imshow(test)

要注意的是用imread读入的图片是RGB色彩空间上的,而要改变图片的亮度属性一般要在HSV空间上操作。一开始没有意识到这点的我一直都在更改B层,还好奇为什么总是显示出一只蓝色的猫……

作业要求代码用python实现于是又写了一遍,注意要实现以下代码要先安装pillow和skimage库,而skimage库又需要很多支持库,总之看着装就是了……

from PIL import Image
from skimage import color
import numpy as np
import matplotlib.pyplot as plt
import math
img=np.array(Image.open('D:/tree.png'))#打开图像并转化为数字矩阵
rows,cols,dims=img.shape
for i in range(0,dims):
	for j in range(0,rows):
		for k in range(0,cols):
			img[j,k,i]=img[j,k,i]&3
imghsv=Image.fromarray(img)#矩阵转换为图像
imghsv=color.rgb2hsv(imghsv)
imghsv=np.array(imghsv)
for i in range(0,rows):
	for j in range(0,cols):
		imghsv[i,j,2]=imghsv[i,j,2]*85
imgrgb=color.hsv2rgb(imghsv)
plt.figure("after")
plt.imshow(imgrgb)
plt.axis('off')
plt.show()

要注意的是用PIL直接读入的图片并不是以矩阵格式保存的,因此要想方便对像素进行操作,可以先把图片转换为矩阵形式。而在矩阵形式下我没有找到便于从RGB颜色空间转换到HSV颜色空间的方法,于是只好又将矩阵转换回PIL的内部形式转换完颜色空间再接着操作……

第二种方式:

要想将一个水印图片加入到另一张图片里去,如果按照上面解码过程的反推则应该要舍弃掉水印图片的大多数信息。如果单纯地将水印图片色彩空间中每一个二进制数的八位的前六位都舍弃掉,那根本就看不出水印里是个啥了(╯’ - ')╯︵ ┻━┻

于是我想到的办法和 @雨诺寒雪 一样,干脆把八位的二进制数分成四块,每块分别加入到载体图片上去,这样能够保证当载体图片的长宽分别为水印图片的长宽的两倍的时候,水印图片的信息不会丢失。不过载体图片还是略有损伤,这点好像是不可避免的……?

上图是载体图片,下图是水印图片,图片来自网络。

这里写图片描述

这里写图片描述

依旧是先上matlab代码:

添加水印部分:

mark=imread('D:/mark.png');
image=imread('D:/image.png');
for i=1:3
for j=1:600
for k=1:600
image(j,k,i)=bitand(image(j,k,i),252);
end
end
end
for i=1:3
for j=1:300
for k=1:300
image(2*j-1,2*k-1,i)=image(2*j-1,2*k-1,i)+bitand(mark(j,k,i),192)/64;
image(2*j-1,2*k,i)=image(2*j-1,2*k,i)+bitand(mark(j,k,i),48)/16;
image(2*j,2*k-1,i)=image(2*j,2*k-1,i)+bitand(mark(j,k,i),12)/4;
image(2*j,2*k,i)=image(2*j,2*k,i)+bitand(mark(j,k,i),3);
end
end
end

提取水印部分:

#前部分同上,省略
result=uint8(zeros(300,300,3));
for i=1:3
for j=1:600
for k=1:600
image(j,k,i)=bitand(image(j,k,i),3);
end
end
end
for i=1:3
for j=1:300
for k=1:300
result(j,k,i)=image(2*j-1,2*k-1,i)*64+image(2*j-1,2*k,i)*16+image(2*j,2*k-1,i)*4+image(2*j,2*k,i);
end
end
end
imshow(result)

同样按照作业要求,再用python写一遍:

添加水印部分:

from PIL import Image
from skimage import color
import numpy as np
import matplotlib.pyplot as plt
import math
img=np.array(Image.open('D:/image.png'))
mark=np.array(Image.open('D:/mark.png'))
rows,cols,dims=mark.shape
for i in range(0,dims):
    for j in range(0,rows*2):
        for k in range(0,cols*2):
            img[j,k,i]=img[j,k,i]&252
for i in range(0,dims):
    for j in range(0,rows):
        for k in range(0,cols):
        	img[2*j,2*k,i]=img[2*j,2*k,i]+(mark[j,k,i]&192)//64
        	img[2*j,2*k+1,i]=img[2*j,2*k+1,i]+(mark[j,k,i]&48)//16
        	img[2*j+1,2*k,i]=img[2*j+1,2*k,i]+(mark[j,k,i]&12)//4
        	img[2*j+1,2*k+1,i]=img[2*j+1,2*k+1,i]+(mark[j,k,i]&3)
img=Image.fromarray(img)
img.save('D:/image_with_mark.png')

提取水印部分:

from PIL import Image
from skimage import color
import numpy as np
import matplotlib.pyplot as plt
import math
imgwmark=np.array(Image.open('D:/image_with_mark.png'))
result=imgwmark
rows,cols,dims=imgwmark.shape
rows=rows//2
cols=cols//2
for i in range(0,dims):
    for j in range(0,rows*2):
        for k in range(0,cols*2):
           imgwmark[j,k,i]=imgwmark[j,k,i]&3
for i in range(0,dims):
    for j in range(0,rows):
        for k in range(0,cols):
        	result[j,k,i]=imgwmark[2*j,2*k,i]*64+imgwmark[2*j,2*k+1,i]*16
        	+imgwmark[2*j+1,2*k,i]*4+imgwmark[2*j+1,2*k+1,i]
mark_get=Image.fromarray(result)
mark_get.save('D:/mark_get.png')

要注意的是,我使用的是python3,在python3中除法(/)的结果默认是float类型的,因此使用向下取整(//)来强制将结果变回整数。

Python3 中有多种实现图片隐写的库,其中常用的有 stegano 和 pillow 等。 以下是使用 pillow 库实现图片隐写的示例代码: ```python from PIL import Image def encode_image(image_path, message): # 打开图片并将其转换为 RGB 模式 img = Image.open(image_path).convert('RGB') pixels = img.load() # 获取图片的宽和高 width, height = img.size # 将待隐藏信息的二进制形式转换为字符串 binary_message = ''.join([format(ord(i), "08b") for i in message]) # 检查隐写信息的长度是否超过了图片的容量 if len(binary_message) > width * height: raise ValueError("待隐藏信息过长") # 开始隐写 index = 0 for row in range(height): for col in range(width): # 将每个像素的 RGB 值转换为二进制形式 r, g, b = pixels[col, row] binary_r = format(r, "08b") binary_g = format(g, "08b") binary_b = format(b, "08b") # 如果还有待隐藏的信息,则将其写入像素的最低有效位中 if index < len(binary_message): pixels[col, row] = ( int(binary_r[:-1] + binary_message[index], 2), int(binary_g[:-1] + binary_message[index+1], 2), int(binary_b[:-1] + binary_message[index+2], 2) ) index += 3 # 保存隐写后的图片 img.save("encoded_image.png") def decode_image(image_path): # 打开图片并将其转换为 RGB 模式 img = Image.open(image_path).convert('RGB') pixels = img.load() # 获取图片的宽和高 width, height = img.size # 从图片中读取隐写信息 message = "" for row in range(height): for col in range(width): r, g, b = pixels[col, row] binary_r = format(r, "08b") binary_g = format(g, "08b") binary_b = format(b, "08b") message += binary_r[-1] + binary_g[-1] + binary_b[-1] # 将二进制信息转换为字符串 decoded_message = "" for i in range(0, len(message), 8): decoded_message += chr(int(message[i:i+8], 2)) return decoded_message ``` 使用示例: ```python # 隐写信息到图片中 encode_image("test.png", "Hello World!") # 从图片中读取隐写信息 message = decode_image("encoded_image.png") print(message) # 输出 "Hello World!" ``` 注意:图片隐写是一种敏感的技,不应用于违法活动或侵犯他人隐私的行为。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值