########## 返回目录 - 信息隐藏技术(Python) ###
1. 同时隐藏嵌入的信息长度,不鲁棒
步骤:
- 将图像切位保留区域(前两行)和嵌入区域两部分
- 在嵌入区域,每个NXN的图像块(block)嵌入一个比特,嵌入方法:
Block DCT
1: block_dct[2, 4] > block_dct[2, 4]- block_dct[2, 4] < block_dct[2, 4]
注:此方法可以扩展到jpg图像,直接修改DCT量化后的系数
import cv2
import numpy as np
import matplotlib.pyplot as plt
import random
def str2bitseq(s, width=8):
'''
Input: s: character string
Output: bit array in np.uint8
'''
binstr = ''.join([(bin(c).replace('0b', '')).zfill(width) for c in s.encode(encoding="utf-8")])
bitseq = [np.uint8(c) for c in binstr]
return bitseq
def bitseq2str(msgbits):
'''
Input: bit array in np.uint8
Output: s: character string
'''
binstr = ''.join([bin(b & 1).strip('0b').zfill(1) for b in msgbits])
str = np.zeros(np.int(len(msgbits)/8)).astype(np.int)
for i in range(0, len(str)):
str[i] = int('0b'+ binstr[(8*i):(8*(i+1))], 2)
return bytes(str.astype(np.int8)).decode()
def getBit(num, bit_idx):
''' From num, get the given bit specified by bit_idx
'''
return (num & (1<<(8-bit_idx))) >> (8-bit_idx)
def dct_embed(img_gray, msg, seed=2020):
"An illustration of how data are embedded in pair-wise DCT coefficients,"
" img_gray - of grayscale"
" msg - the to be embedded msg composed of 0 and 1 only"
" seed - the encryption password"
if len(img_gray.shape) > 2:
print("Parameter img should be of grayscale")
return img_gray
# Step 1: check embedding capacity
msg2embed = str2bitseq(msg)
len_msg = len(msg2embed)
# print(len_msg, msg2embed)
# EC: embedding capacity
# The first two rows of the image is preserved from data hiding
# but for hiding some data bits for the len of msg
# Besides, 1 bit is hided in each N by N block
N = 8
height, width = img_gray.shape
EC = np.int((height-2)*(width)/N/N)
if EC < len_msg:
print('Embedding Capacity {} not enough'.format(EC))
return img_gray
# encrypted msg2embed
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
bits2embed = np.bitwise_xor(msg2embed, np.uint8(s))
# print('To embed:', bits2embed)
# Step 2 data embedding via pair-wise DCT ordering
# Embeddeding starts from the bottom-right corner
img = img_gray[2:, :].copy()
height, width = img.shape
cnt = 0
delta = 0.01
for row in np.arange(0, height, N):
if cnt >= len_msg:
break
for col in np.arange(0, width, N):
if cnt >= len_msg:
break
# embedding one bit in 1 pair of DCT coefficients
block = np.array(img[row:(row+N), col:(col+N)], np.float32)
block_dct = cv2.dct(block)
a, b = (block_dct[2, 4], block_dct[4, 2]) if block_dct[2, 4]>block_dct[4, 2] else (block_dct[4, 2], block_dct[2, 4])
a += delta
b -= delta
block_dct[2, 4] = (a if bits2embed[cnt] == 1 else b) # make block_dct[2, 3] > block_dct[3, 2]
block_dct[4, 2] = (b if bits2embed[cnt] == 1 else a) # make block_dct[3, 2] < block_dct[2, 3]
cnt += 1
img[row:(row+N), col:(col+N)] = np.array(cv2.idct(block_dct), np.uint8)
# step 3: hide auxillary information
bits_bin = (bin(len_msg).replace('0b', '')).zfill(24)
# print(bits_bin)
img_marked = img_gray.copy()
for i, bit in enumerate(bits_bin):
img_marked[0, i] &= (255-1)
img_marked[0, i] += np.uint8(bits_bin[i])
img_marked[2:, :] = img
return img_marked
def dct_extract(img_marked, seed=2020):
"An illustration of data extraction to the previous embedding,"
" img_marked - of grayscale"
" seed - the password for decryption"
if len(img_marked.shape) > 2:
print("Parameter img should be of grayscale")
return img_marked
# Step 1: Extract auxillary information
bits_bin = ''
for i in range(24):
bits_bin += bin(img_marked[0, i] & 1).strip('0b').zfill(1)
# print(bits_bin)
len_msg = int('0b'+bits_bin, 2)
N = 8
img = img_marked[2:, :]
height, width = img.shape
msg_embedded = ''
cnt = 0
for row in np.arange(0, height, N):
if cnt >= len_msg:
break
for col in np.arange(0, width, N):
if cnt >= len_msg:
break
# embedding one bit in 1 pair of DCT coefficients
block = np.array(img[row:(row+N), col:(col+N)], np.float32)
block_dct = cv2.dct(block)
msg_embedded += ('1' if block_dct[2, 4]>block_dct[4, 2] else '0')
cnt += 1
bits_extracted = [np.uint8(c) for c in msg_embedded]
# print('Extracted:', bits_extracted)
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
msgbits = np.bitwise_xor(bits_extracted, np.uint8(s))
msg = bitseq2str(msgbits)
return msg
if __name__ == '__main__':
img_file = './monarch.png'
msg = '图像DCT嵌入'
img_gray = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)
img_marked = dct_embed(img_gray, msg, 20200417)
cv2.imwrite('monarch_marked.png', img_marked)
print(img_marked.shape, type(img_marked), type(img_marked[0,0]))
img_stego = cv2.imread('monarch_marked.png', cv2.IMREAD_GRAYSCALE)
msg_out = dct_extract(img_stego, 20200417)
print('嵌入的信息为:', msg)
print('提取的信息为:', msg_out)
plt.figure(figsize=(4,3))
plt.subplot(121), plt.imshow(img_gray, cmap='gray'), plt.title('Cover')
plt.subplot(122), plt.imshow(img_marked, cmap='gray'), plt.title('Marked')
plt.tight_layout()
plt.show()
嵌入的信息为: 图像DCT嵌入
提取的信息为: 图像DCT嵌入
Cover and Mark
2. 不嵌入信息长度,鲁棒
import cv2
import numpy as np
import matplotlib.pyplot as plt
import random
def str2bitseq(s, width=8):
'''
Input: s: character string
Output: bit array in np.uint8
'''
binstr = ''.join([(bin(c).replace('0b', '')).zfill(width) for c in s.encode(encoding="utf-8")])
bitseq = [np.uint8(c) for c in binstr]
return bitseq
def bitseq2str(msgbits):
'''
Input: bit array in np.uint8
Output: s: character string
'''
binstr = ''.join([bin(b & 1).strip('0b').zfill(1) for b in msgbits])
str = np.zeros(np.int(len(msgbits)/8)).astype(np.int)
for i in range(0, len(str)):
str[i] = int('0b'+ binstr[(8*i):(8*(i+1))], 2)
return bytes(str.astype(np.int8)).decode()
def getBit(num, bit_idx):
''' From num, get the given bit specified by bit_idx
'''
return (num & (1<<(8-bit_idx))) >> (8-bit_idx)
def dct_embed(img_gray, msg, seed=2020):
"An illustration of how data are embedded in pair-wise DCT coefficients,"
" img_gray - of grayscale"
" msg - the to be embedded msg composed of 0 and 1 only"
" seed - the encryption password"
if len(img_gray.shape) > 2:
print("Parameter img should be of grayscale")
return img_gray
# Step 1: check embedding capacity
msg2embed = str2bitseq(msg)
len_msg = len(msg2embed)
# print(len_msg, msg2embed)
# EC: embedding capacity
# 1 bit is hided in each N by N block
N = 8
height, width = img_gray.shape
EC = np.int((height)*(width)/N/N)
if EC < len_msg:
print('Embedding Capacity {} not enough'.format(EC))
return img_gray
# encrypted msg2embed
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
bits2embed = np.bitwise_xor(msg2embed, np.uint8(s))
# print('To embed:', bits2embed)
# Step 2 data embedding via pair-wise DCT ordering
# Embeddeding starts from the bottom-right corner
img_marked = img_gray.copy()
height, width = img_marked.shape
cnt = 0
delta = 10
r0, c0 = 2, 3
for row in np.arange(0, height-N, N):
if cnt >= len_msg:
break
for col in np.arange(0, width-N, N):
if cnt >= len_msg:
break
# embedding one bit in 1 pair of DCT coefficients
block = np.array(img_marked[row:(row+N), col:(col+N)], np.float32)
block_dct = cv2.dct(block)
a, b = (block_dct[r0, c0], block_dct[c0, r0]) if block_dct[r0, c0]>block_dct[c0, r0] else (block_dct[c0, r0], block_dct[r0, c0])
a += delta
b -= delta
block_dct[r0, c0] = (a if bits2embed[cnt] == 1 else b)
block_dct[c0, r0] = (b if bits2embed[cnt] == 1 else a)
cnt += 1
img_marked[row:(row+N), col:(col+N)] = np.array(cv2.idct(block_dct), np.uint8)
return img_marked, len_msg
def dct_extract(img_marked, len_msg, seed=2020):
"An illustration of data extraction to the previous embedding,"
" img_marked - of grayscale"
" seed - the password for decryption"
if len(img_marked.shape) > 2:
print("Parameter img should be of grayscale")
return img_marked
N = 8
height, width = img_marked.shape
msg_embedded = ''
cnt = 0
r0, c0 = 2, 3
for row in np.arange(0, height-N, N):
if cnt >= len_msg:
break
for col in np.arange(0, width-N, N):
if cnt >= len_msg:
break
# embedding one bit in 1 pair of DCT coefficients
block = np.array(img_marked[row:(row+N), col:(col+N)], np.float32)
block_dct = cv2.dct(block)
msg_embedded += ('1' if block_dct[r0, c0]>block_dct[c0, r0] else '0')
cnt += 1
bits_extracted = [np.uint8(c) for c in msg_embedded]
# print('Extracted:', bits_extracted)
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
msgbits = np.bitwise_xor(bits_extracted, np.uint8(s))
msg = bitseq2str(msgbits)
return msg
if __name__ == '__main__':
img_file = './monarch.png'
msg = '图像DCT嵌入'
img_gray = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)
img_marked, len_msg = dct_embed(img_gray, msg, 20200417)
cv2.imwrite('monarch_marked.jpg', img_marked, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
print(img_marked.shape, type(img_marked), type(img_marked[0,0]))
img_stego = cv2.imread('monarch_marked.jpg', cv2.IMREAD_GRAYSCALE)
msg_out = dct_extract(img_stego, len_msg, 20200417)
print('嵌入的信息为:', msg)
print('提取的信息为:', msg_out)
plt.figure(figsize=(4,3))
plt.subplot(121), plt.imshow(img_gray, cmap='gray'), plt.title('Cover')
plt.subplot(122), plt.imshow(img_stego, cmap='gray'), plt.title('Marked')
plt.tight_layout()
plt.show()
JPG压缩
########## 返回目录 - 信息隐藏技术(Python) ###