########## 返回目录 - 信息隐藏技术(Python) ###
此例通过直方图扩展的方法嵌入一定数量的文字,嵌入容量取决于图像直方图最大的两个bin,所以可以称为pair-wise的直方图扩展嵌入方法。
注:
- 嵌入和提取方法的输入图像为灰度图
- 嵌入和提取的信息为字符串
- 此例可稍作修改后适用于多彩图、多pair-wise直方图扩展嵌入
源代码如下
import cv2
import numpy as np
import matplotlib.pyplot as plt
import random
def str2bitseq(s, width=8):
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):
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)
print(str)
return bytes(str.astype(np.int8)).decode()
def find2bins(hist):
"hist - list of histogram frequency"
idx = sorted(range(len(hist)), key=lambda k: hist[k], reverse=True)
a = idx[0] if idx[0] < idx[1] else idx[1]
b = idx[1] if idx[0] < idx[1] else idx[0]
return a, b
def getBit(num, bit_idx):
return (num & (1<<(8-bit_idx))) >> (8-bit_idx)
def getHist(img_gray):
"Get the histogram of img, where"
"img is of grayscale"
hist = cv2.calcHist(images=[img_gray], channels=[0], mask=None, histSize=[256], ranges=[0,256])
return list(hist.astype(np.uint32).reshape((1,256))[0])
def peh_embed(img_gray, msg, seed=2020):
"An illustration of how data are embedded in LSBs vis histogram embedding,"
" 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)
# encrypted msg2embed
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
msg2embed = np.bitwise_xor(msg2embed, np.uint8(s))
# print(len_msg, np.sum(msg2embed)/len_msg, msg2embed)
# EC: embedding capacity
# The first row of the img is preserved from data hiding
# but for hiding some data bits for ha, hb and the len of msg
hist = getHist(img_gray[1:, :])
ha, hb = find2bins(hist)
print(ha, hist[ha], hb, hist[hb])
mask_lha = np.array(img_gray[1:, :]==ha).astype(np.uint8)
mask_lhb = np.array(img_gray[1:, :]==hb).astype(np.uint8)
EC = np.sum(mask_lha) + np.sum(mask_lhb)
if EC < len_msg:
print('Embedding Capacity {} not enough'.format(EC))
return img_gray
# Step 2 data embedding via histogram expansion
img_marked = np.copy(img_gray)
img_marked[img_marked<ha] = img_marked[img_marked<ha] - 1
img_marked[img_marked>hb] = img_marked[img_marked>hb] + 1
height, width = img_marked.shape
cnt = 0
for row in np.arange(1, height):
if cnt >= len_msg:
break
for col in np.arange(0, width):
if cnt >= len_msg:
break
# pixel = img[row, col]
bit = msg2embed[cnt]
# print(bit)
if img_marked[row, col] == ha:
img_marked[row, col] -= bit
cnt += 1
elif img_marked[row, col] == hb:
img_marked[row, col] += bit
cnt += 1
# step 3: hide auxillary information
bits_bin = (bin(ha).replace('0b', '')).zfill(8)
bits_bin += ((bin(hb).replace('0b', '')).zfill(8))
bits_bin += ((bin(len_msg).replace('0b', '')).zfill(24))
# print(bits_bin)
for i, bit in enumerate(bits_bin):
img_marked[0, i] &= (255-1)
img_marked[0, i] += np.uint8(bits_bin[i])
return img_marked
def peh_extract(img_marked, seed=2020):
"An illustration of how data are embedded in LSBs vis histogram 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(8+8+24):
bits_bin += bin(img_marked[0, i] & 1).strip('0b').zfill(1)
# print(bits_bin)
ha = int('0b'+bits_bin[0:8], 2)
hb = int('0b'+bits_bin[8:(8+8)], 2)
len_msg = int('0b'+bits_bin[(8+8):(8+8+24)], 2)
# print(ha, hb, len_msg)
height, width = img_marked.shape
msg_embedded = ''
cnt = 0
for row in np.arange(1, height):
if cnt >= len_msg:
break
for col in np.arange(0, width):
if cnt >= len_msg:
break
if img_marked[row, col] == ha or img_marked[row, col] == hb:
msg_embedded += '0'
cnt += 1
elif img_marked[row, col] == ha-1 or img_marked[row, col] == hb+1:
msg_embedded += '1'
cnt += 1
bits_embedded = [np.uint8(c) for c in msg_embedded]
random.seed(seed)
s = [random.randint(0,1) for i in range(len_msg)]
msgbits = np.bitwise_xor(bits_embedded, np.uint8(s))
msg = bitseq2str(msgbits)
return msg
if __name__ == '__main__':
img_file = './monarch.png'
msg = '图像算术运算'
img_gray = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)
img_marked = peh_embed(img_gray, msg)
cv2.imwrite('monarch_marked.png', img_marked)
img_stego = cv2.imread('monarch_marked.png', cv2.IMREAD_GRAYSCALE)
msg_out = peh_extract(img_marked)
print('嵌入的信息为:', msg)
print('提取的信息为:', msg_out)
hist = getHist(img_gray[1:, :])
hist_marked = getHist(img_marked[1:, :])
x_index = list(np.arange(0, 256))
plt.figure(figsize=(4,2))
# plt.subplot(211),
plt.bar(x_index, hist, 1, color='r')
plt.bar(x_index, hist_marked, 1, color='b')
# plt.subplot(212), plt.bar(x_index, hist_marked, 1, color='b')
plt.legend(('Cover', 'Marked'))
plt.show()
输出:
嵌入的信息为: 图像算术运算
提取的信息为: 图像算术运算
########## 返回目录 - 信息隐藏技术(Python) ###