Image steganography, how to hide QR code in image

I. Introduction

There is an encrypted watermark function in an App, when the owner of the post turns it on. If someone takes a screenshot, then this screenshot is to add the screenshot user, post ID, screenshot time and other information, and we can't see these watermarks with the naked eye.

This can be achieved through the steganography technology to be introduced today, through which we will use the Python language and the OpenCV module to implement the operation of hiding QR codes in images. And this QR code cannot be seen with the naked eye.

2. Steganography

Steganography is a technique similar to but different from encryption. Usually, encryption is a transformation of the data itself, and the result is a bunch of data that cannot be read by people. For example, the result of md5 encryption of "Hello" is "7eca689f0d3389d9dea66ae112e5cfd7". content, but we know this should be encrypted data. The purpose of steganography is also to allow only the receiver to obtain the data, but steganography is usually more covert, and steganography is more focused on not letting third parties know that there is additional information in the data I send.

Just like some plots we often see in movies, a seemingly ordinary dialogue contains a lot of information that outsiders do not know, which is actually a kind of steganography. Another example is "This is a pig", which looks like an ordinary sentence. If both parties specify that "T, i, s" occupy two letters on the three-line grid to represent 0, and "p, g" occupy three lines The letter below the two squares represents 1, then this sentence can be translated as "0000000101". And today we are going to introduce the "least significant bit" steganography.

3. Bit plane decomposition

Before introducing the "least significant bit" steganography, it is necessary to understand some image related knowledge. This includes digital images, bit planes, and bit plane decomposition.

3.1 Images

In a computer, an image is represented as a matrix of numbers, each number is called a pixel, and their values ​​are in the [0, 255] interval, which can be represented by 8 binary numbers.

The size of this matrix is ​​determined by the image resolution. If it is a 480×480 resolution image, then the matrix size is 480×480. If it is a color image, it will be represented by three matrices of the same size, which represent the degree of image R (red), G (green), and B (blue), which is commonly known as RGB image.

We can use OpenCV to read the image. The installation of OpenCV is as follows:

pip install opencv-python

Once installed you can read the image:

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

where test.jpgis our image name or image path. The output of the above code is as follows:

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

Because the output is too long, part of the content is omitted here.

3.2 Bit plane

Earlier we said that an image is a digital matrix, such as:

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

We can understand it as a simple image, and now we write the pixel value of the image in binary form:

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

We take out the highest bits of the four pixels to get a new image:

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

An illustration of this process is as follows:

insert image description here

The image taken out here is called the bit plane, because it is an image composed of the seventh bit (7-0 from left to right), so it is called the seventh bit plane, also called the highest bit plane. The 0th bit plane is also called the "least significant bit" bit plane.

If the 1st bit is taken out, the resulting image is:

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

This image is called the first bit plane. One thing to note here is that the actual value of each bit plane should be multiplied by a weight, the weight bit i 2, that is, the weight bit 7 2 of the seventh bit plane.

3.3 Bit plane decomposition

Let's see how to decompose the bit plane. Decomposing the bit plane can be implemented with the cv2.bitwise_and function. We need to pass in an image and a decomposition factor. The decomposition factors of each bit plane are as follows:

decomposition factor effect
0x80 Decompose the 7th bit plane
0x40 Decompose the 6th bit plane
0x20 Decompose the 5th bit plane
0x10 Decompose the 4th bit plane
0x08 Decompose the 3rd bit plane
0x04 Decompose the 2nd bit plane
0x02 Decompose the 1st bit plane
0x11 Decompose the 0th bit plane

For example, the operation of decomposing the 7th bit plane is:

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

The decomposition of other bit planes only needs to be modified according to the table.

3.4 Bit plane synthesis

If we decompose and decompose 8 bit planes, they are M0, M1, ..., M7. We only need to multiply each bit plane by the corresponding weight, and then add it to restore the original image, namely:

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

If we only synthesize M1-M7, the difference between A` and A is at most 1, so we can make A`≈A. At this point the 0th bit plane of image A' can be used to hide data.

Fourth, image steganography

Here we use a technique called "least significant bit" bit plane steganography to hide the QR code. The principle is to set the "least significant bit" bit plane of the image to 0. At this time, the difference between the pixel of the image and the original image is at most 0, and the human eye cannot see the difference. Then we can arbitrarily set the value in the least significant bit of the image. At this time, the maximum difference between the image and the original image pixel is still 1. This allows us to steganographic data with the "least significant" bit plane.

In the previous, we used M1-M7 when synthesizing the original image, and the M0 bit plane was all 0. At this time, we can use the least significant bit to store data. If our data matrix is ​​M, the matrix is ​​a 0-1 matrix. The two-dimensional code is a black and white matrix, we can regard black as 0 and white as 1, so we let M be a matrix of a two-dimensional code. Now we synthesize it by the following formula:

A shading = M + ∑ i = 1 7 i 2 × M i A_{shaking} = M + \sum_{i=1}^{7}{i^2 × M_i}ASteganography=M+i=17i2×Mi

This A is an image with steganographic information. The code is implemented as follows:

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])

The last saved dst.png is our steganographic image.

The generation of QR code can refer to the blog: https://blog.csdn.net/ZackSock/article/details/105222763

Code for steganography and parsing (no points required): https://download.csdn.net/download/ZackSock/83785652

Guess you like

Origin blog.csdn.net/ZackSock/article/details/126735402