一、前言

在某个App中有一个加密水印的功能,当帖子的主人开启了之后。如果有人截图,那么这张截图中就是添加截图用户、帖子ID、截图时间等信息,而且我们无法用肉眼看出这些水印。

这可以通过今天要介绍的隐写技术来实现,我们会通过这种技术,借助Python语言和OpenCV模块来实现在图像中隐藏二维码的操作。而且这个二维码无法通过肉眼看出。

二、隐写

隐写是一种类似于加密却又不同于加密的技术。通常情况下,加密是对数据本身进行一个转换,得到的结果是一堆人无法解读的数据,比如“你好”进行md5加密后的结果是“7eca689f0d3389d9dea66ae112e5cfd7”,如果光看“7eca689f0d3389d9dea66ae112e5cfd7”我们不知道内容,但是我们知道这应该是加密后的数据。隐写的目的同样是让只有接收方才能获取数据,但是隐写通常更加隐蔽,隐写更注重于不让第三方知道我发送的数据中有额外信息。

就像我们在电影中经常看到的一些剧情,一场看似普通的对话却隐含了许多外人不知道的信息,这实际上就是一种隐写。再比如“This is a pig”,看上去像一个普通的句子,如果通信双方规定“T、i、s”这些占三线格上两个的字母表示0,而“p、g”这种占三线格下两格的字母表示1,那么这句话就可以翻译成“0000000101”。而今天我们要介绍的是“最低有效位”隐写。

三、位平面分解

在介绍“最低有效位”隐写之前,需要了解一些图像相关的知识。这里包括数字图像、位平面、位平面分解。

3.1 图像

在计算机中,图像被表示为一个数字矩阵,每个数字被称为一个像素,它们的取值在[0, 255]区间,可以用8个二进制来表示。

这个矩阵大小由图像分辨率决定,如果是480×480分辨率的图像,那么这个矩阵大小就是480×480。如果是彩色图像,会用三个大小相同的矩阵合起来表示,它们分别表示图像R(红色)、G(绿色)、B(蓝色)的程度,也就是俗称的RGB图像。

我们可以用OpenCV来读取图像,OpenCV的安装如下:

pip install opencv-python

安装完成后就可以读取图像:

# 导入模块
import cv2
# 读取图像
img = cv2.imread('test.jpg')
# 输出图像
print(img)

其中test.jpg就是我们的图像名称或者图像路径。上面代码输出结果如下:

[[[ 72 220 234][ 72 220 234][ 73 221 235] ...[ 87 147 176][ 87 147 176][ 87 147 176]]]

因为输出过长,这里省略了一部分内容。

3.2 位平面

在前面我们说了一个图像是一个数字矩阵,比如:

[[2, 2]
[3, 4]]

我们可以理解为一张简单的图像,现在我们把图像的像素值写成二进制形式:

[[0000 0010, 0000 0010],
[0000 0011, 0000 0100]]

我们把四个像素的最高位取出,得到新的图像:

[[0, 0]
[0, 0]]

这个过程的图示如下:

这里取出来的图像就叫位平面,因为是取出第7位(从左到右依次是7-0)组成的图像,所以叫第7位平面,也叫最高位平面。而第0位平面也叫“最低有效位”位平面。

如果取出第1位,得到的图像为:

[[1, 1],
[1, 0]]

这个图像叫第1位平面。这里需要注意一点,就是每个位平面的实际值应该乘一个权重,这个权重位i2,即第7位平面的权重位72。

3.3 位平面分解

下面我们看看如何分解位平面,分解位平面可以用cv2.bitwise_and函数来实现。我们需要传入一个图像以及一个分解因子,各个位平面的分解因子如下:

分解因子 作用
0x80 分解第7位平面
0x40 分解第6位平面
0x20 分解第5位平面
0x10 分解第4位平面
0x08 分解第3位平面
0x04 分解第2位平面
0x02 分解第1位平面
0x11 分解第0位平面

比如分解第7位平面的操作为:

import cv2
# 读取图像
img = cv2.imread('test.jpg', 0)
# 分解第7位平面
layer = cv2.bitwise_and(img, 0x80)

其它位平面的分解只需要对照表进行修改即可。

3.4 位平面合成

假如我们以及分解出来8个位平面,分别是M0、M1、…、M7。我们只需要将各个位平面乘上对应的权重,然后相加就能恢复原图,即:

A=∑i=07i2×MiA = \sum_{i=0}^{7}{i^2 × M_i} A=i=0∑7​i2×Mi​

如果我们只对M1-M7进行合成,得到的A`与A的差距最多为1,因此我们可以让A`≈A。此时图像A`的第0个位平面可以用于隐藏数据。

四、图像隐写

这里我们使用一种叫“最低有效位”位平面隐写的技术来实现二维码的隐藏。其原理就是把图像“最低有效位”位平面设置为0,此时图像与原图像像素相差最大为0,人肉眼无法看出区别。然后我们可以在图像的最低有效位任意设置值,此时图像与原图像素相差最大仍是1。这样我们就可以用“最低有效位”位平面来隐写数据。

在前面我们合成原图时用M1-M7,而M0位平面则全为0,这时我们可以用最低有效位存储数据。假如我们的数据矩阵为M,该矩阵为一个0-1矩阵。而二维码就是一个黑白矩阵,我们可以把黑当作0,白当作1,这样我们让M为一个二维码的矩阵。现在我们通过下面的公式来合成:

A隐写=M+∑i=17i2×MiA_{隐写} = M + \sum_{i=1}^{7}{i^2 × M_i} A隐写​=M+i=1∑7​i2×Mi​

这个A就是带有隐写信息的图像。代码实现如下:

import cv2
# ①读取图像
img = cv2.imread('test.jpg', 0)
# ②把最低有效位清空
img -= cv2.bitwise_and(img, 0x01)
# ③准备需要隐写的信息M
M = cv2.imread('qrcode.jpg', 0)
M = cv2.resize(M, img.shape)
# 把二维码转换成0-1矩阵
_, M = cv2.threshold(M, 30, 1, cv2.THRESH_BINARY)
# ④将要隐写的数据设置到图像最低有效位
img += M
# ⑥以无损的方式保存隐写后的
cv2.imwrite('dst.png', img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])

最后保存的dst.png就是我们隐写后的图像。

二维码的生成可以参考博客:https://blog.csdn.net/ZackSock/article/details/105222763

隐写与解析的代码(不需要积分):https://download.csdn.net/download/ZackSock/83785652

图像隐写,如何在图像中隐藏二维码相关推荐

  1. Android 基于google Zxing实现对手机中的二维码进行扫描

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/14450809 我之前写了一篇关于google Zxing扫描二维码的文章,效果是仿微信 ...

  2. 在java中生成二维码,并直接输出到jsp页面

    在java中生成的二维码不存到磁盘里要直接输出到页面上,这就需要把生成的二维码直接以流的形式输出到页面上,我用的是myeclipse 和 tomcat 它的原理是:在加载页面时,根据img的src(c ...

  3. Java和C#环境中制作二维码图片

    二维码作为一种先进的应用,随着移动互联网和智能终端的普及而快速发展,在媒体.产品质量.仓储物流登各行各业都应用广泛.二维码具有存储量大.保密性高.追踪性高.抗损性强.被援性大.成本便宜等特性,这些特性 ...

  4. java完整的利用itext5制作pdf、二维码图片插入pdf,并解析pdf中的二维码信息

    利用itext5.zxing.QRCore制作pdf.二维码图片插入pdf,并解析pdf中的二维码信息,手机可以实现扫描获取二维码的信息,并进行验证你的解析是否正确. 先是生成二维码图片并插入pdf中 ...

  5. Vue中生成二维码的一种方式—vue-qr

    Vue中生成二维码的一种方式-vue-qr vue实现二维码生成(vue + vue-qr)

  6. C#_WPF中创建二维码、识别二维码

    C#_WPF中创建二维码.识别二维码 原文: C#_WPF中创建二维码.识别二维码 第三方库: WPFMediaKit.dll (WPFMediaKit摄像头处理) zing.dll NuGet安装这 ...

  7. 微信二维码图片长按没有出现“识别图中的二维码”

    2019独角兽企业重金招聘Python工程师标准>>> 问题:页面中显示二维码图片,但是长按没有出现"识别图中二维码"选项. 1有说是style 的问题,然而修改 ...

  8. 96微信编辑器如何将样式中的二维码替换成自己的?

    现在我们编辑公众号时候,都会在后面放上公众号的二维码,引导客户识别关注.96微信编辑器上也有这样的功能,可以放很多个性样式的二维码.但是怎么替换成自己的二维码呢?这里教给大家一些. 一.在微信公众平台 ...

  9. 贴吧猫头鹰隐藏二维码是怎么制作的?

    贴吧猫头鹰隐藏二维码是怎么制作的? 这里有个问题大家要明白, 最终是防删, 而不是做的多漂亮,当然追求漂亮也不是错的,但用我们用户的最终角度来说还是要防删,防删才是核心. 第一:如果你要做一张好看的猫 ...

最新文章

  1. grub legacy
  2. Rancher前奏--配置Nexus
  3. 「Tensorflow」TensorFlow基本使用步骤——以线性回归为练习
  4. SAP Spartacus 开发规范
  5. 508. 出现次数最多的子树元素和
  6. Android 系统(74)--Android重启原因分析
  7. 小米发布2021年第二季度财报:小米手机二季度平均售价1116.7元
  8. web 折线图大数据量拉取展示方案_对比多种微前端方案
  9. BP神经网络从理论到应用(一):C++实现
  10. python zfill_Python字符串zfill()
  11. 用一个div模拟textarea的实现【前端每日一题-15】
  12. Atitit.各种 数据类型 ( 树形结构,表形数据 ) 的结构与存储数据库 attilax 总结
  13. 拟凸函数一阶条件的证明
  14. alize blue_泽野弘之 | 明明可以靠才华,却非要用脸滚键盘的神曲缔造者
  15. CodeSmith链接Oracle、MySQL数据库
  16. linux查看日志的几种方法
  17. Qt QLineEdit自带右键菜单的翻译
  18. code flattening —— conversion to R1CS——formulation of QAP
  19. IMU输出的角度、角速度、加速度信息的坐标系
  20. QuickBI-云数据库数据源

热门文章

  1. 青岛旅行网页毕设HTML 带报告讲解5个充实超链接页面 大学生网页 旅游网页
  2. 如何选择分度带(中央子午线)
  3. 且夫天地为炉兮,造化为工;阴阳为炭兮,万物为铜。合散消息兮,安有常则?千变万化兮,未始有极,忽然为人兮,何足控抟;化为异物兮,又何足患!
  4. ubuntu 极点五笔/万能五笔 for ibus
  5. Java弱引用(WeakReference)
  6. B1016_部分A+B
  7. java 判定全角空格_JAVA中半角和全角的判定
  8. 2014年各大网站编辑/主编薪资大曝光
  9. c语言地铁收费程序,地铁管理系统C语言源程序
  10. matlab 频谱图例子_利用matlab怎样进行频谱分析